home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Entertainment / MacMud / Mud 4.0 / simulate.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-26  |  77.0 KB  |  3,120 lines  |  [TEXT/MPS ]

  1. #include "config.h"
  2.  
  3. #include <types.h>
  4. #include <quickdraw.h>
  5. #include <sys/types.h>
  6. #include <mac.h>
  7. #include <setjmp.h>
  8. #include <string.h>
  9. #include <errno.h>
  10. #include <stdio.h>
  11. #include <memory.h>
  12.  
  13. #include "lint.h"
  14. #include "nlhack.h"
  15. #include "stdio.h"
  16. #include "lang.h"
  17. #include "interpret.h"
  18. #include "object.h"
  19. #include "sent.h"
  20. #include "wiz_list.h"
  21. #include "exec.h"
  22. #include "comm.h"
  23. #include "rc.h"
  24.  
  25. extern int errno;
  26. extern int comp_flag;
  27.  
  28. int new_name_count;
  29. char *inherit_file;
  30.  
  31. extern int readlink PROT((char *, char *, int));
  32. extern int symlink PROT((char *, char *));
  33. extern int fstat PROT((int, struct stat *));
  34. #ifndef MSDOS
  35. extern int lstat PROT((char *, struct stat *));
  36. #else
  37. #define lstat stat
  38. #endif
  39. extern int fchmod PROT((int, int));     
  40. char *last_verb;
  41.  
  42. extern int special_parse PROT((char *)),
  43.     set_call PROT((struct object *, struct sentence *, int)),
  44.     legal_path PROT((char *));
  45. extern char *findstring PROT ((char *));
  46.  
  47. void pre_compile PROT((char *)),
  48.     remove_interactive PROT((struct object *)),
  49.     add_light PROT((struct object *, int)),
  50.     add_action PROT((char *, char *, int)),
  51.     add_verb PROT((char *, int)),
  52.     print_local_commands(), ipc_remove(),
  53.     show_info_about PROT((char *, char *, struct interactive *)),
  54.     set_snoop PROT((struct object *, struct object *)),
  55.     print_lnode_status PROT((int)), remove_all_players(),
  56.     start_new_file PROT((FILE *, int)),
  57.     end_new_file(),
  58.     move_or_destruct PROT((struct object *, struct object *)),
  59.     load_ob_from_swap PROT((struct object *)), dump_malloc_data(),
  60.     print_svalue PROT((struct svalue *)),
  61.     debug_message_value(),
  62.     destruct2();
  63.  
  64. extern int d_flag;
  65.  
  66. struct object *obj_list, *obj_list_destruct, *master_ob;
  67.  
  68. extern struct wiz_list *back_bone_uid;
  69.  
  70. struct object *current_object;      /* The object interpreting a function. */
  71. struct object *command_giver;       /* Where the current command came from. */
  72. struct object *current_interactive; /* The user who caused this execution */
  73.  
  74. int num_parse_error;        /* Number of errors in the parser. */
  75.  
  76. void shutdowngame();
  77.  
  78. extern void flush_all_player_mess();
  79.  
  80. struct variable *find_status(str, must_find)
  81.     char *str;
  82.     int must_find;
  83. {
  84.     int i;
  85.     char *shared_str;
  86.  
  87.     if (shared_str = findstring(str)) {
  88.     for (i=0; i < current_object->prog->num_variables; i++) {
  89.         if (current_object->prog->variable_names[i].name == shared_str)
  90.         return ¤t_object->prog->variable_names[i];
  91.     }
  92.     }
  93.     if (!must_find)
  94.     return 0;
  95.     error("--Status %s not found in prog for %s\n", str,
  96.        current_object->name);
  97.     return 0;
  98. }
  99.  
  100. /*
  101.  * Give the correct uid and euid to a created object.
  102.  */
  103. int give_uid_to_object(ob)
  104.     struct object *ob;
  105. {
  106.     struct object *tmp_ob;
  107. #ifdef COMPAT_MODE
  108.     char wiz_name[100];
  109. #else
  110.     struct svalue *ret;
  111.     char *creator_name;
  112. #endif
  113.  
  114.     if (master_ob == 0)
  115.     tmp_ob = ob;
  116.     else {
  117.     assert_master_ob_loaded();
  118.     tmp_ob = master_ob;
  119.     }
  120.     
  121. #ifdef COMPAT_MODE
  122.     /* Is this object wizard defined ? */
  123.     if (sscanf(ob->name, "players/%s", wiz_name) == 1) {
  124.     char *np;
  125.     np = strchr(wiz_name, '/');
  126.     if (np)
  127.         *np = '\0';
  128.     ob->user = add_name(wiz_name);
  129.     } else {
  130.     ob->user = 0;
  131.     }
  132. #ifdef NLHACK
  133.     set_eff_user(ob);
  134. #else
  135.     ob->eff_user = ob->user;    /* Initial state */
  136. #endif
  137.     return 1;
  138. #else
  139.  
  140.     if (!current_object || !current_object->user) {
  141.     /*
  142.      * Only for the master and void object. Note that
  143.      * back_bone_uid is not defined when master.c is being loaded.
  144.      */
  145.     ob->user = add_name("NONAME");
  146.     ob->eff_user = 0;
  147.     return 1;
  148.     }
  149.  
  150.     /*
  151.      * Ask master.c who the creator of this object is.
  152.      */
  153.     push_string(ob->name, STRING_CONSTANT);
  154.     ret = apply("creator_file", tmp_ob, 1);
  155.     if (!ret)
  156.     error("No function 'creator_file' in master.c!\n");
  157.     if (ret->type != T_STRING) {
  158.     struct svalue arg;
  159.     /* This can be the case for objects in /ftp and /open. */
  160.     arg.type = T_OBJECT;
  161.     arg.u.ob = ob;
  162.     destruct_object(&arg);
  163.     error("Illegal object to load.\n");
  164.     }
  165.     creator_name = ret->u.string;
  166.     /*
  167.      * Now we are sure that we have a creator name.
  168.      * Do not call apply() again, because creator_name will be lost !
  169.      */
  170.     if (strcmp(current_object->user->name, creator_name) == 0) {
  171.     /* 
  172.      * The loaded object has the same uid as the loader.
  173.      */
  174.     ob->user = current_object->eff_user;
  175.     ob->eff_user = current_object->eff_user;
  176.     return 1;
  177.     }
  178.  
  179.     if (strcmp(back_bone_uid->name, creator_name) == 0) {
  180.     /*
  181.      * The object is loaded from backbone. This is trusted, so we
  182.      * let it inherit the value of eff_user.
  183.      */
  184.     ob->user = current_object->eff_user;
  185.     ob->eff_user = current_object->eff_user;
  186.     return 1;
  187.     }
  188.  
  189.     /*
  190.      * The object is not loaded from backbone, nor from 
  191.      * from the loading objects path. That should be an object
  192.      * defined by another wizard. It can't be trusted, so we give it the
  193.      * same uid as the creator. Also give it eff_user 0, which means that
  194.      * player 'a' can't use objects from player 'b' to load new objects nor
  195.      * modify files owned by player 'b'.
  196.      *
  197.      * If this effect is wanted, player 'b' must let his object do
  198.      * 'seteuid()' to himself. That is the case for most rooms.
  199.      */
  200.     ob->user = add_name(creator_name);
  201.     ob->eff_user = (struct wiz_list *)0;
  202.     return 1;
  203. #endif /* COMPAT_MODE */
  204. }
  205.  
  206. /*
  207.  * Load an object definition from file. If the object wants to inherit
  208.  * from an object that is not loaded, discard all, load the inherited object,
  209.  * and reload again.
  210.  *
  211.  * In mudlib3.0 when loading inherited objects, their reset() is not called.
  212.  *
  213.  * Save the command_giver, because reset() in the new object might change
  214.  * it.
  215.  *
  216.  */
  217. struct object *load_object(lname, dont_reset, level)
  218.     char *lname;
  219.     int dont_reset, level;
  220. {
  221.     FILE *f;
  222.     extern int total_lines;
  223.     extern int approved_object;
  224.  
  225.     struct object *ob, *save_command_giver = command_giver;
  226.     extern struct program *prog;
  227.     extern char *current_file;
  228.     struct stat c_st;
  229.     int name_length;
  230.     char real_name[200], name[200];
  231.  
  232. #ifndef COMPAT_MODE
  233.     if (current_object && current_object->eff_user == 0)
  234.     error("Can't load objects when no effective user.\n");
  235. #endif
  236.     /* Truncate possible .c in the object name. */
  237.     /* Remove leading '/' if any. */
  238.     while(lname[0] == '/')
  239.     lname++;
  240.     strncpy(name, lname, sizeof(name) - 1);
  241.     name[sizeof name - 1] = '\0';
  242.     name_length = strlen(name);
  243.     if (name_length > sizeof name - 4)
  244.     name_length = sizeof name - 4;
  245.     name[name_length] = '\0';
  246.     if (name[name_length-2] == '.' && name[name_length-1] == 'c') {
  247.     name[name_length-2] = '\0';
  248.     name_length -= 2;
  249.     }
  250.     /*
  251.      * First check that the c-file exists.
  252.      */
  253.     (void)strcpy(real_name, name);
  254.     (void)strcat(real_name, ".c");
  255.     if (stat(real_name, &c_st) == -1) {
  256.     fprintf(stderr, "Could not load descr for %s\n", real_name);
  257.     error("Failed to load file.\n");
  258.     return 0;
  259.     }
  260.     /*
  261.      * Check if it's a legal name.
  262.      */
  263.     if (!legal_path(real_name)) {
  264.     fprintf(stderr, "Illegal pathname: %s\n", real_name);
  265.     error("Illegal path name.\n");
  266.     return 0;
  267.     }
  268.     if (comp_flag)
  269.     fprintf(stderr, " compiling %s ...", real_name);
  270.     if ((f = fopen(real_name, "r")) == NULL) {
  271.         perror(real_name);
  272.         error("Could not read the file.\n");
  273.     }
  274.     current_file = string_copy(real_name);    /* This one is freed below */
  275.     start_new_file(f, level);
  276.     compile_file();
  277.     end_new_file();
  278.     if (comp_flag)
  279.         fprintf(stderr, " done\n");
  280.     update_compile_av(total_lines);
  281.     total_lines = 0;
  282.     (void)fclose(f);
  283.     xfree(current_file);
  284.     current_file = 0;
  285.     /* Sorry, can't handle objects without programs yet. */
  286.     if (inherit_file == 0 && (num_parse_error > 0 || prog == 0)) {
  287.     if (prog)
  288.         free_prog(prog, 1);
  289.     if (num_parse_error == 0 && prog == 0)
  290.         error("No program in object !\n");
  291.     error("Error in loading object\n");
  292.     }
  293.     /*
  294.      * This is an iterative process. If this object wants to inherit an
  295.      * unloaded object, then discard current object, load the object to be
  296.      * inherited and reload the current object again. The global variable
  297.      * "inherit_file" will be set by lang.y to point to a file name.
  298.      */
  299.     if (inherit_file) {
  300.     char *tmp = inherit_file;
  301.     if (prog) {
  302.         free_prog(prog, 1);
  303.         prog = 0;
  304.     }
  305.     if (strcmp(inherit_file, name) == 0) {
  306.         xfree(inherit_file);
  307.         inherit_file = 0;
  308.         error("Illegal to inherit self.\n");
  309.     }
  310.     inherit_file = 0;
  311. #if 1 /* MUDLIB3_NEED, It's very awkard to have to have a debug3 /JnA */
  312. #ifdef COMPAT_MODE
  313.     load_object(tmp, 0, level+1);
  314. #else    
  315.     load_object(tmp, 1, level+1);
  316. #endif
  317. #else
  318.     load_object(tmp, 0, level+1);    /* Remove this feature for now */
  319. #endif
  320.     xfree(tmp);
  321.     ob = load_object(name, dont_reset, level);
  322.     return ob;
  323.     }
  324.     ob = get_empty_object(prog->num_variables);
  325.     /*
  326.      * Can we approve of this object ?
  327.      */
  328.     if (approved_object || strcmp(prog->name, "std/object.c") == 0)
  329.     ob->flags |= O_APPROVED;
  330.     ob->name = string_copy(name);    /* Shared string is no good here */
  331.     ob->prog = prog;
  332.     ob->next_all = obj_list;
  333.     obj_list = ob;
  334.     enter_object_hash(ob);    /* add name to fast object lookup table */
  335.  
  336.     if (give_uid_to_object(ob) && !dont_reset)
  337.     reset_object(ob, 0);
  338.     if (!(ob->flags & O_DESTRUCTED) && function_exists("clean_up",ob)) {
  339.     ob->flags |= O_WILL_CLEAN_UP;
  340.     }
  341.     command_giver = save_command_giver;
  342.     if (d_flag > 1 && ob)
  343.     debug_message("--%s loaded\n", ob->name);
  344.     return ob;
  345. }
  346.  
  347. char *make_new_name(str)
  348.     char *str;
  349. {
  350.     char *p = xalloc(strlen(str) + 10);
  351.  
  352.     (void)sprintf(p, "%s#%d", str, new_name_count);
  353.     new_name_count++;
  354.     return p;
  355. }
  356.     
  357.  
  358. /*
  359.  * Save the command_giver, because reset() in the new object might change
  360.  * it.
  361.  */
  362. struct object *clone_object(str1)
  363.     char *str1;
  364. {
  365.     struct object *ob, *new_ob;
  366.     struct object *save_command_giver = command_giver;
  367.  
  368. #ifndef COMPAT_MODE
  369.     if (current_object && current_object->eff_user == 0)
  370.     error("Illegal to call clone_object() with effective user 0\n");
  371. #endif
  372.     ob = find_object(str1);
  373.     /*
  374.      * If the object self-destructed...
  375.      */
  376.     if (ob == 0)
  377.     return 0;
  378.     if (ob->super || (ob->flags & O_CLONE))
  379.     error("Cloning a bad object !\n");
  380.     
  381.     /* We do not want the heart beat to be running for unused copied objects */
  382.  
  383.     if (ob->flags & O_HEART_BEAT) 
  384.     (void)set_heart_beat(ob, 0);
  385.     new_ob = get_empty_object(ob->prog->num_variables);
  386.     new_ob->name = make_new_name(ob->name);
  387.     new_ob->flags |= O_CLONE | ob->flags & ( O_APPROVED | O_WILL_CLEAN_UP ) ;
  388. #if 0
  389.     if (ob->flags & O_APPROVED)
  390.     new_ob->flags |= O_APPROVED;
  391. #endif
  392.     new_ob->prog = ob->prog;
  393.     reference_prog (ob->prog, "clone_object");
  394. #ifdef COMPAT_MODE
  395.     if (current_object && current_object->user && !ob->user)
  396.     new_ob->user = current_object->user;
  397.     else
  398.     new_ob->user = ob->user;        /* Possibly a null pointer */
  399. #ifdef NLHACK
  400.     set_eff_user(new_ob);
  401. #else
  402.     new_ob->eff_user = new_ob->user;    /* Init state */
  403. #endif
  404. #else 
  405.     if (!current_object)
  406.     fatal("clone_object() from no current_object !\n");
  407.     
  408.     give_uid_to_object(new_ob);
  409.  
  410. #endif
  411.     new_ob->next_all = obj_list;
  412.     obj_list = new_ob;
  413.     enter_object_hash(new_ob);    /* Add name to fast object lookup table */
  414.     reset_object(new_ob, 0); 
  415.     command_giver = save_command_giver;
  416.     /* Never know what can happen ! :-( */
  417.     if (new_ob->flags & O_DESTRUCTED)
  418.     return 0;
  419.     return new_ob;
  420. }
  421.  
  422. struct object *environment(arg)
  423.     struct svalue *arg;
  424. {
  425.     struct object *ob = current_object;
  426.  
  427.     if (arg && arg->type == T_OBJECT)
  428.     ob = arg->u.ob;
  429.     else if (arg && arg->type == T_STRING)
  430.     ob = find_object2(arg->u.string);
  431.     if (ob == 0 || ob->super == 0 || (ob->flags & O_DESTRUCTED))
  432.     return 0;
  433.     if (ob->flags & O_DESTRUCTED)
  434.     error("environment() off destructed object.\n");
  435.     return ob->super;
  436. }
  437.  
  438. /*
  439.  * Execute a command for an object. Copy the command into a
  440.  * new buffer, because 'parse_command()' can modify the command.
  441.  * If the object is not current object, static functions will not
  442.  * be executed. This will prevent forcing players to do illegal things.
  443.  *
  444.  * Return cost of the command executed if success (> 0).
  445.  * When failure, return 0.
  446.  */
  447. int command_for_object(str, ob)
  448.     char *str;
  449.     struct object *ob;
  450. {
  451.     char buff[1000];
  452.     extern int eval_cost;
  453.     int save_eval_cost = eval_cost - 1000;
  454.  
  455.     if (strlen(str) > sizeof(buff) - 1)
  456.     error("Too long command.\n");
  457.     if (ob == 0)
  458.     ob = current_object;
  459.     else if (ob->flags & O_DESTRUCTED)
  460.     return 0;
  461.     strncpy(buff, str, sizeof buff);
  462.     buff[sizeof buff - 1] = '\0';
  463.     if (parse_command(buff, ob))
  464.     return eval_cost - save_eval_cost;
  465.     else
  466.     return 0;
  467. }
  468.  
  469. /*
  470.  * To find if an object is present, we have to look in two inventory
  471.  * lists. The first list is the inventory of the current object.
  472.  * The second list is all things that have the same ->super as
  473.  * current_object.
  474.  * Also test the environment.
  475.  * If the second argument 'ob' is non zero, only search in the
  476.  * inventory of 'ob'. The argument 'ob' will be mandatory, later.
  477.  */
  478.  
  479. static struct object *object_present2 PROT((char *, struct object *));
  480.  
  481. struct object *object_present(v, ob)
  482.     struct svalue *v;
  483.     struct object *ob;
  484. {
  485.     struct svalue *ret;
  486.     struct object *ret_ob;
  487.     int specific = 0;
  488.  
  489.     if (ob == 0)
  490.     ob = current_object;
  491.     else
  492.     specific = 1;
  493.     if (ob->flags & O_DESTRUCTED)
  494.     return 0;
  495.     if (v->type == T_OBJECT) {
  496.     if (specific) {
  497.         if (v->u.ob->super == ob)
  498.         return v->u.ob;
  499.         else
  500.         return 0;
  501.     }
  502.     if (v->u.ob->super == ob ||
  503.         (v->u.ob->super == ob->super && ob->super != 0))
  504.         return v->u.ob->super;
  505.     return 0;
  506.     }
  507.     ret_ob = object_present2(v->u.string, ob->contains);
  508.     if (ret_ob)
  509.     return ret_ob;
  510.     if (specific)
  511.     return 0;
  512.     if (ob->super) {
  513.     push_string(v->u.string, STRING_CONSTANT);
  514.     ret = apply("id", ob->super, 1);
  515.     if (ob->super->flags & O_DESTRUCTED)
  516.         return 0;
  517.     if (ret && !(ret->type == T_NUMBER && ret->u.number == 0))
  518.         return ob->super;
  519.     return object_present2(v->u.string, ob->super->contains);
  520.     }
  521.     return 0;
  522. }
  523.  
  524. static struct object *object_present2(str, ob)
  525.     char *str;
  526.     struct object *ob;
  527. {
  528.     struct svalue *ret;
  529.     char *p;
  530.     int count = 0, length;
  531.     char *item;
  532. #ifdef NLHACK
  533.     int invis;
  534. #endif
  535.  
  536.     item = string_copy(str);
  537.     length = strlen(item);
  538.     p = item + length - 1;
  539.     if (*p >= '0' && *p <= '9') {
  540.     while(p > item && *p >= '0' && *p <= '9')
  541.         p--;
  542.     if (p > item && *p == ' ') {
  543.         count = atoi(p+1) - 1;
  544.         *p = '\0';
  545.         length = p - item;    /* This is never used again ! */
  546.     }
  547.     }
  548. #ifdef NLHACK
  549.     invis = !command_giver || !(command_giver->flags & O_CAN_SEE_HINVIS);
  550. #endif
  551.     for (; ob; ob = ob->next_inv) {
  552.     push_string(item, STRING_CONSTANT);
  553.     ret = apply("id", ob, 1);
  554.     if (ob->flags & O_DESTRUCTED) {
  555.         xfree(item);
  556.         return 0;
  557.     }
  558.     if (ret == 0 || (ret->type == T_NUMBER && ret->u.number == 0))
  559.         continue;
  560. #ifdef NLHACK
  561.     if (invis && (ob->flags & O_HARD_INVIS))
  562.         continue;
  563. #endif
  564.     if (count-- > 0)
  565.         continue;
  566.     xfree(item);
  567.     return ob;
  568.     }
  569.     xfree(item);
  570.     return 0;
  571. }
  572.  
  573. /*
  574.  * Remove an object. It is first moved into the destruct list, and
  575.  * not really destructed until later. (see destruct2()).
  576.  */
  577. void destruct_object(v)
  578.     struct svalue *v;
  579. {
  580.     struct object *ob, *super;
  581.     struct object **pp;
  582.     int removed;
  583.  
  584.     if (v->type == T_OBJECT)
  585.     ob = v->u.ob;
  586.     else {
  587.     ob = find_object2(v->u.string);
  588.     if (ob == 0)
  589.         error("destruct_object: Could not find %s\n", v->u.string);
  590.     }
  591. #ifdef NLHACK
  592.     if (ob == master_ob)
  593.     error("Illegal to destruct master object.\n");
  594. #endif
  595.     if (ob->flags & O_DESTRUCTED)
  596.     return;
  597.     if (ob->flags & O_SWAPPED)
  598.     load_ob_from_swap(ob);
  599.     remove_object_from_stack(ob);
  600.     /*
  601.      * If this is the first object being shadowed by another object, then
  602.      * destruct the whole list of shadows.
  603.      */
  604.     if (ob->shadowed && !ob->shadowing) {
  605.     struct svalue svp;
  606.     struct object *ob2;
  607.  
  608.     svp.type = T_OBJECT;
  609.     for (ob2 = ob->shadowed; ob2; ) {
  610.         svp.u.ob = ob2;
  611.         ob2 = ob2->shadowed;
  612.         svp.u.ob->shadowed = 0;
  613.         svp.u.ob->shadowing = 0;
  614.         destruct_object(&svp);
  615.     }
  616.     }
  617.     /*
  618.      * The chain of shadows is a double linked list. Take care to update
  619.      * it correctly.
  620.      */
  621.     if (ob->shadowing)
  622.     ob->shadowing->shadowed = ob->shadowed;
  623.     if (ob->shadowed)
  624.     ob->shadowed->shadowing = ob->shadowing;
  625.     ob->shadowing = 0;
  626.     ob->shadowed = 0;
  627.  
  628.     if (ob->flags & O_DESTRUCTED)
  629.     return;
  630.  
  631.     if (d_flag > 1)
  632.     debug_message("Destruct object %s (ref %d)\n", ob->name, ob->ref);
  633.     super = ob->super;
  634.     if (super) {
  635. #ifdef COMPAT_MODE
  636.     struct svalue *weight;
  637.     /* Call exit in current room, if player or npc not in mudlib 3.0 */
  638.     if((ob->flags & O_ENABLE_COMMANDS)) {
  639.         push_object(ob);
  640.         (void)apply("exit",super,1);
  641.         if (ob->flags & O_DESTRUCTED)
  642.         return;
  643.     }
  644.     weight = apply("query_weight", ob, 0);
  645.     if (ob->flags & O_DESTRUCTED)
  646.         return;
  647.     if (weight && weight->type == T_NUMBER) {
  648.         push_number(-weight->u.number);
  649.         (void)apply("add_weight", super, 1);
  650.         if (ob->flags & O_DESTRUCTED)
  651.         return;
  652.     }
  653. #endif
  654.     }
  655.     if (super == 0) {
  656.     /*
  657.      * There is nowhere to move the objects.
  658.      */
  659.     struct svalue svp;
  660.     svp.type = T_OBJECT;
  661.     while(ob->contains) {
  662.         svp.u.ob = ob->contains;
  663.         push_object(ob->contains);
  664.         /* An error here will not leave destruct() in an inconsistent
  665.          * stage.
  666.          */
  667.         apply_master_ob("destruct_environment_of",1);
  668.         if (svp.u.ob == ob->contains)
  669.         destruct_object(&svp);
  670.     }
  671.     } else {
  672.     while(ob->contains)
  673.         move_or_destruct(ob->contains, super);
  674.     }
  675.     if (ob->flags & O_DESTRUCTED)
  676.     return;
  677.     if ( ob->interactive ) {
  678.     struct object *save=command_giver;
  679.  
  680.     command_giver=ob;
  681.     if (ob->interactive->ed_buffer) {
  682.         extern void save_ed_buffer();
  683.  
  684.         save_ed_buffer();
  685.     }
  686.     flush_all_player_mess();
  687.     command_giver=save;
  688.     }
  689.     set_heart_beat(ob, 0);
  690.     /*
  691.      * Remove us out of this current room (if any).
  692.      * Remove all sentences defined by this object from all objects here.
  693.      */
  694.     if (ob->super) {
  695.     if (ob->super->flags & O_ENABLE_COMMANDS)
  696.         remove_sent(ob, ob->super);
  697.     add_light(ob->super, - ob->total_light);
  698.     for (pp = &ob->super->contains; *pp;) {
  699.         if ((*pp)->flags & O_ENABLE_COMMANDS)
  700.         remove_sent(ob, *pp);
  701.         if (*pp != ob)
  702.         pp = &(*pp)->next_inv;
  703.         else
  704.         *pp = (*pp)->next_inv;
  705.     }
  706.     }
  707.     /*
  708.      * Now remove us out of the list of all objects.
  709.      * This must be done last, because an error in the above code would
  710.      * halt execution.
  711.      */
  712.     removed = 0;
  713.     for (pp = &obj_list; *pp; pp = &(*pp)->next_all) {
  714.     if (*pp != ob)
  715.         continue;
  716.     *pp = (*pp)->next_all;
  717.     removed = 1;
  718.     remove_object_hash(ob);
  719.     break;
  720.     }
  721.     if (!removed)
  722.         fatal("Failed to delete object.\n");
  723.     if (ob->living_name)
  724.     remove_living_name(ob);
  725.     ob->super = 0;
  726.     ob->next_inv = 0;
  727.     ob->contains = 0;
  728.     ob->flags &= ~O_ENABLE_COMMANDS;
  729.     ob->next_all = obj_list_destruct;
  730.     obj_list_destruct = ob;
  731.     ob->flags |= O_DESTRUCTED;
  732. }
  733.  
  734. /*
  735.  * This one is called when no program is executing from the main loop.
  736.  */
  737. void destruct2(ob)
  738.     struct object *ob;
  739. {
  740.     if (d_flag > 1) {
  741.     debug_message("Destruct-2 object %s (ref %d)\n", ob->name, ob->ref);
  742.     }
  743.     if (ob->interactive)
  744.     remove_interactive(ob);
  745.     /*
  746.      * We must deallocate variables here, not in 'free_object()'.
  747.      * That is because one of the local variables may point to this object,
  748.      * and deallocation of this pointer will also decrease the reference
  749.      * count of this object. Otherwise, an object with a variable pointing
  750.      * to itself, would never be freed.
  751.      * Just in case the program in this object would continue to
  752.      * execute, change string and object variables into the number 0.
  753.      */
  754.     if (ob->prog->num_variables > 0) {
  755.     /*
  756.      * Deallocate variables in this object.
  757.      * The space of the variables are not deallocated until
  758.      * the object structure is freed in free_object().
  759.      */
  760.     int i;
  761.     for (i=0; i<ob->prog->num_variables; i++) {
  762.         free_svalue(&ob->variables[i]);
  763.         ob->variables[i].type = T_NUMBER;
  764.         ob->variables[i].u.number = 0;
  765.     }
  766.     }
  767.     free_object(ob, "destruct_object");
  768. }
  769.  
  770. #ifdef F_CREATE_WIZARD
  771. /*
  772.  * This is the efun create_wizard(). Create a home dir for a wizard,
  773.  * and other files he may want.
  774.  *
  775.  * The real job is done by the master.c object, so the call could as well
  776.  * have been done to it directly. But, this function remains for
  777.  * compatibility.
  778.  *
  779.  * It should be replaced by a function in simul_efun.c !
  780.  */
  781. char *create_wizard(owner, domain)
  782.     char *owner;
  783.     char *domain;
  784. {
  785.     struct svalue *ret;
  786. #if 0
  787.     struct stat st;
  788.     FILE *f;
  789.     char cmd[200], lbuf[128];
  790.     static char name[200], name2[200];    /* Ugly fix /Lars (static) */
  791.     struct object *owner_obj;
  792. #endif
  793.  
  794.     /*
  795.      * Let the master object do the job.
  796.      */
  797.     push_constant_string(owner);
  798.     push_constant_string(domain);
  799.     push_object(current_object);
  800.     ret = apply_master_ob("master_create_wizard", 3);
  801.     if (ret && ret->type == T_STRING)
  802.     return ret->u.string;
  803.     return 0;
  804. #if 0
  805.     /*
  806.      * Verify that it is a valid call of create_wizard(). This is done
  807.      * by a function in master.c. It will take the calling object as
  808.      * argument, and must return a non-zero value.
  809.      */
  810.     push_object(current_object);
  811.     ret = apply_master_ob("verify_create_wizard", 1);
  812.     if (ret == 0)
  813.     error("No wizards allowed ! (because no verify_create_wizard() in master.c)\n");
  814.     if (ret->type == T_NUMBER && ret->u.number == 0)
  815.     error("Illegal use of create_wizard() !\n");
  816.  
  817.     /*
  818.      * Even if the object that called create_wizard() is trusted, we won't
  819.      * allow it to use funny names for the owner.
  820.      */
  821.     if (!legal_path(owner))
  822.     error("Bad name to create_wizard: %s\n", owner);
  823.  
  824.     owner_obj = find_living_object(owner, 1);
  825.     if (owner_obj == 0) {
  826.     fprintf(stderr,
  827.         "create_wizard: Could not find living object %s.\n", owner);
  828.     return 0;
  829.     }
  830.  
  831.     /*
  832.      * Create the path to wizards home directory.
  833.      */
  834.     (void)sprintf(name, "%s/%s", PLAYER_DIR, owner);
  835.  
  836.     /*
  837.      * If we are using domains, make a path to the domain.
  838.      */
  839.     if(domain) {
  840.     (void)sprintf(name2, "%s/%s/%s", DOMAIN_DIR, domain, owner);
  841.     fprintf(stderr, "name = %s, name2 =  %s\n", name, name2);
  842.  
  843.     /*
  844.      * If the directory already exists, we move it to the domain.
  845.      */
  846.     if (stat(name, &st) == 0) {
  847.         if((st.st_mode & S_IFMT) == S_IFDIR) {
  848.         rename(name, name2);
  849.         }
  850.     } else {
  851.         if (mkdir(name2, 0777) == -1) {
  852.         perror(name2);
  853.         error("Could not mkdir %s\n", name2);
  854.         }
  855.     }
  856.     } else {
  857.     if (stat(name, &st) == 0)
  858.         error("Player %s already has a castle!\n", owner);
  859.  
  860.     else
  861.         if (mkdir(name, 0777) == -1) {
  862.         perror(name);
  863.         error("Could not mkdir %s\n", name);
  864.         }
  865.     }
  866.  
  867.     /* add castle */
  868.     if(domain) {
  869.     (void)sprintf(name, "%s/%s/common/domain.c", DOMAIN_DIR, domain);
  870.     } else {
  871.     (void)sprintf(name, "%s/%s/%s", PLAYER_DIR, owner, "castle.c");
  872.     }
  873.     if(stat(name, &st) == 0) {
  874.     fprintf(stderr, "castle file %s already exists.\n", name);
  875.     } else {
  876.     f = fopen(name, "w");
  877.     if (f == NULL)
  878.         error("Could not create a castle file %s!\n", name);
  879.     (void)fprintf(f, "#define NAME \"%s\"\n", domain ? domain : owner);
  880. #ifdef CASTLE_ROOM
  881.     (void)fprintf(f, "#define DEST \"%s\"\n", CASTLE_ROOM);
  882. #else
  883.     (void)fprintf(f, "#define DEST \"%s\"\n",
  884.               current_object->super->name);
  885. #endif
  886.     (void)fclose(f);
  887.     (void)sprintf(cmd, "cat %s >> %s", DEFAULT_CASTLE, name);
  888.     (void)system(cmd);
  889.     }
  890.     
  891.     /*
  892.      * Add this castle name to the list of files to be loaded.
  893.      */
  894.     f = fopen(INIT_FILE, "a");
  895.     if (f == NULL)
  896.     error("Could not add the new castle to the %s\n", INIT_FILE);
  897.     (void)fprintf(f, "%s\n", name);
  898.     (void)fclose(f);
  899.     return name;
  900. #endif
  901. }
  902. #endif /* F_CREATE_WIZARD */
  903.  
  904. /*
  905.  * A message from an object will reach
  906.  * all objects in the inventory,
  907.  * all objects in the same environment and
  908.  * the surrounding object.
  909.  * Non interactive objects gets no messages.
  910.  *
  911.  * There are two cases to take care of. If this routine is called from
  912.  * a player (indirectly), then the message goes to all in his
  913.  * environment. Otherwise, the message goes to all in the current_object's
  914.  * environment (as the case when called from a heart_beat()).
  915.  *
  916.  * If there is a second argument 'avoid_ob', then do not send the message
  917.  * to that object.
  918.  */
  919.  
  920. void say(v, avoid)
  921.     struct svalue *v;
  922.     struct vector *avoid;
  923. {
  924.     extern struct vector *order_alist PROT((struct vector *));
  925.     struct vector *vtmpp;
  926.     static struct vector vtmp = { 1, 1,
  927. #ifdef DEBUG
  928.     1,
  929. #endif
  930.     (struct wiz_list *)NULL,
  931.     { { T_POINTER } }
  932.     };
  933.  
  934.     extern int assoc PROT((struct svalue *key, struct vector *));
  935.     struct object *ob, *save_command_giver = command_giver;
  936.     struct object *origin;
  937.     char buff[256];
  938. #define INITIAL_MAX_RECIPIENTS 50
  939.     int max_recipients = INITIAL_MAX_RECIPIENTS;
  940.     struct object *first_recipients[INITIAL_MAX_RECIPIENTS];
  941.     struct object **recipients = first_recipients;
  942.     struct object **curr_recipient = first_recipients;
  943.     struct object **last_recipients =
  944.     &first_recipients[INITIAL_MAX_RECIPIENTS-1];
  945.  
  946.     struct object *save_again;
  947.     static struct svalue stmp = { T_OBJECT };
  948.  
  949.     if (current_object->flags & O_ENABLE_COMMANDS)
  950.     command_giver = current_object;
  951.     else if (current_object->shadowing)
  952.     command_giver = current_object->shadowing;
  953.     if (command_giver) {
  954.     origin = command_giver;
  955.         if (avoid->item[0].type == T_NUMBER) {
  956.             avoid->item[0].type = T_OBJECT;
  957.             avoid->item[0].u.ob = command_giver;
  958.             add_ref(command_giver, "ass to var");
  959.         }
  960.     } else
  961.     origin = current_object;
  962.     vtmp.item[0].u.vec = avoid;
  963.     vtmpp = order_alist(&vtmp);
  964.     avoid = vtmpp->item[0].u.vec;
  965.     if (ob = origin->super) {
  966.     if (ob->flags & O_ENABLE_COMMANDS || ob->interactive) {
  967.         *curr_recipient++ = ob;
  968.     }
  969.     for (ob = origin->super->contains; ob; ob = ob->next_inv) {
  970.             if (ob->flags & O_ENABLE_COMMANDS || ob->interactive) {
  971.                 if (curr_recipient >= last_recipients) {
  972.                     max_recipients <<= 1;
  973.                     curr_recipient = (struct object **)
  974.               alloca(max_recipients * sizeof(struct object *));
  975.                     memcpy((char*)curr_recipient, (char*)recipients,
  976.                       max_recipients * sizeof(struct object *)>>1);
  977.                     recipients = curr_recipient;
  978.                     last_recipients = &recipients[max_recipients-1];
  979.             curr_recipient += (max_recipients>>1) - 1;
  980.                 }
  981.                 *curr_recipient++ = ob;
  982.             }
  983.     }
  984.     }
  985.     for (ob = origin->contains; ob; ob = ob->next_inv) {
  986.     if (ob->flags & O_ENABLE_COMMANDS || ob->interactive) {
  987.         if (curr_recipient >= last_recipients) {
  988.         max_recipients <<= 1;
  989.         curr_recipient = (struct object **)alloca(max_recipients);
  990.         memcpy((char*)curr_recipient, (char*)recipients,
  991.           max_recipients * sizeof(struct object *)>>1);
  992.         recipients = curr_recipient;
  993.         last_recipients = &recipients[max_recipients-1];
  994.         curr_recipient += (max_recipients>>1) - 1;
  995.         }
  996.         *curr_recipient++ = ob;
  997.     }
  998.     }
  999.     *curr_recipient = (struct object *)0;
  1000.     switch(v->type) {
  1001.     case T_STRING:
  1002.     strncpy(buff, v->u.string, sizeof buff);
  1003.     buff[sizeof buff - 1] = '\0';
  1004.     break;
  1005.     case T_OBJECT:
  1006.     strncpy(buff, v->u.ob->name, sizeof buff);
  1007.     buff[sizeof buff - 1] = '\0';
  1008.     break;
  1009.     case T_NUMBER:
  1010.     sprintf(buff, "%d", v->u.number);
  1011.     break;
  1012.     case T_POINTER:
  1013.     for (curr_recipient = recipients; ob = *curr_recipient++; ) {
  1014.         extern void push_vector PROT((struct vector *));
  1015.  
  1016.         if (ob->flags & O_DESTRUCTED) continue;
  1017.         stmp.u.ob = ob;
  1018.         if (assoc(&stmp, avoid) >= 0) continue;
  1019.         push_vector(v->u.vec);
  1020.         push_object(command_giver);
  1021.         apply("catch_msg", ob, 2);
  1022.     }
  1023.     break;
  1024.     default:
  1025.     error("Invalid argument %d to say()\n", v->type);
  1026.     }
  1027.     save_again = command_giver;
  1028.     for (curr_recipient = recipients; ob = *curr_recipient++; ) {
  1029.         if (ob->flags & O_DESTRUCTED) continue;
  1030.     stmp.u.ob = ob;
  1031.     if (assoc(&stmp, avoid) >= 0) continue;
  1032.     if (ob->interactive == 0) {
  1033.         tell_npc(ob, buff);
  1034.         continue;
  1035.     }
  1036.     command_giver = ob;
  1037.     add_message("%s", buff);
  1038.     command_giver = save_again;
  1039.     }
  1040.     free_vector(vtmpp);
  1041.     command_giver = save_command_giver;
  1042. }
  1043.  
  1044. /*
  1045.  * Send a message to all objects inside an object.
  1046.  * Non interactive objects gets no messages.
  1047.  * Compare with say().
  1048.  */
  1049.  
  1050. void tell_room(room, v, avoid)
  1051.     struct object *room;
  1052.     struct svalue *v;
  1053.     struct vector *avoid; /* has to be in alist order */
  1054. {
  1055.     struct object *ob, *save_command_giver = command_giver;
  1056.     char buff[256];
  1057.  
  1058.     switch(v->type) {
  1059.     case T_STRING:
  1060.     strncpy(buff, v->u.string, sizeof buff);
  1061.     buff[sizeof buff - 1] = '\0';
  1062.     break;
  1063.     case T_OBJECT:
  1064.     strncpy(buff, v->u.ob->name, sizeof buff);
  1065.     buff[sizeof buff - 1] = '\0';
  1066.     break;
  1067.     case T_NUMBER:
  1068.     sprintf(buff, "%d", v->u.number);
  1069.     break;
  1070.     default:
  1071.     error("Invalid argument %d to tell_room()\n", v->type);
  1072.     }
  1073.     for (ob = room->contains; ob; ob = ob->next_inv) {
  1074.         int assoc PROT((struct svalue *key, struct vector *));
  1075.     static struct svalue stmp = { T_OBJECT, } ;
  1076.  
  1077.     stmp.u.ob = ob;
  1078.     if (assoc(&stmp, avoid) >= 0) continue;
  1079.     if (ob->interactive == 0) {
  1080.         if (ob->flags & O_ENABLE_COMMANDS) {
  1081.         /*
  1082.          * We want the monster code to have a correct this_player()
  1083.          */
  1084.         command_giver = save_command_giver;
  1085.         tell_npc(ob, buff);
  1086.         }
  1087.         if (ob->flags & O_DESTRUCTED)
  1088.         break;
  1089.         continue;
  1090.     }
  1091.     command_giver = ob;
  1092.     add_message("%s", buff);
  1093.     }
  1094.     command_giver = save_command_giver;
  1095. }
  1096.  
  1097. void shout_string(str)
  1098.     char *str;
  1099. {
  1100.     struct object *ob, *save_command_giver = command_giver;
  1101.     extern int num_player;
  1102.     extern struct interactive **all_players;
  1103.     int i, n;
  1104. #ifdef LOG_SHOUT
  1105.     FILE *f = 0;
  1106. #endif
  1107.     char *p;
  1108. #ifdef NLHACK
  1109.     struct svalue *muffled;
  1110. #endif
  1111.  
  1112.     str = string_copy(str);    /* So that we can modify the string */
  1113.     for (p=str; *p; p++) {
  1114.     if ((*p < ' ' || *p > '~') && *p != '\n')
  1115.         *p = ' ';
  1116.     }
  1117.  
  1118.     p = 0;
  1119. #ifdef LOG_SHOUT
  1120.     if (command_giver) {
  1121.     struct svalue *v;
  1122.     v = apply("query_real_name", command_giver, 0);
  1123.     if (v && v->type == T_STRING)
  1124.         p = v->u.string;
  1125.     } else if (current_object && current_object->user)
  1126.     p = current_object->user->name;
  1127.     if (p)
  1128.     f = fopen("log/SHOUTS", "a");
  1129.     if (f) {
  1130.     fprintf(f, "%s: %s\n", p, str);
  1131.     fclose(f);
  1132.     }
  1133. #endif
  1134.     for (i = 0, n = num_player; n; i++) {
  1135.     if (!all_players[i])
  1136.         continue;
  1137.     n--;
  1138.     ob = all_players[i]->ob;
  1139.     if (ob == save_command_giver || !ob->super)
  1140.         continue;
  1141. #ifdef NLHACK
  1142.     muffled = apply("query_muffled", ob, 0);
  1143.     if (muffled && muffled->type == T_NUMBER && muffled->u.number == 1)
  1144.         continue;
  1145. #endif
  1146.     command_giver = ob;
  1147.     add_message("%s", str);
  1148.     }
  1149.     command_giver = save_command_giver;
  1150.     xfree(str);
  1151. }
  1152.  
  1153. struct object *first_inventory(arg)
  1154.     struct svalue *arg;
  1155. {
  1156.     struct object *ob;
  1157. #ifdef NLHACK
  1158.     int invis;
  1159. #endif
  1160.  
  1161.     if (arg->type == T_STRING)
  1162.     ob = find_object(arg->u.string);
  1163.     else
  1164.     ob = arg->u.ob;
  1165.     if (ob == 0)
  1166.     error("No object to first_inventory()");
  1167.     if (ob->contains == 0)
  1168.     return 0;
  1169. #ifdef NLHACK
  1170.     ob = ob->contains;
  1171.     invis = !command_giver || !(command_giver->flags & O_CAN_SEE_HINVIS);
  1172.     while (ob && invis && (ob->flags & O_HARD_INVIS))
  1173.     ob = ob->next_inv;
  1174.     return ob;
  1175. #else
  1176.     return ob->contains;
  1177. #endif
  1178. }
  1179.  
  1180. /*
  1181.  * This will enable an object to use commands normally only
  1182.  * accessible by interactive players.
  1183.  * Also check if the player is a wizard. Wizards must not affect the
  1184.  * value of the wizlist ranking.
  1185.  */
  1186.  
  1187. void enable_commands(num)
  1188.     int num;
  1189. {
  1190.     if (current_object->flags & O_DESTRUCTED)
  1191.     return;
  1192.     if (d_flag > 1) {
  1193.     debug_message("Enable commands %s (ref %d)\n",
  1194.         current_object->name, current_object->ref);
  1195.     }
  1196.     if (num) {
  1197.     current_object->flags |= O_ENABLE_COMMANDS;
  1198.     command_giver = current_object;
  1199.     } else {
  1200.     current_object->flags &= ~O_ENABLE_COMMANDS;
  1201.     if (command_giver == current_object)
  1202.         command_giver = 0;
  1203.     }
  1204. }
  1205.  
  1206. /*
  1207.  * Set up a function in this object to be called with the next
  1208.  * user input string.
  1209.  */
  1210. int input_to(fun, flag)
  1211.     char *fun;
  1212.     int flag;
  1213. {
  1214.     struct sentence *s;
  1215.  
  1216.     if (!command_giver || command_giver->flags & O_DESTRUCTED)
  1217.     return 0;
  1218.     s = alloc_sentence();
  1219.     if (set_call(command_giver, s, flag)) {
  1220.     s->function = make_shared_string(fun);
  1221.     s->ob = current_object;
  1222.     add_ref(current_object, "input_to");
  1223.     return 1;
  1224.     }
  1225.     free_sentence(s);
  1226.     return 0;
  1227. }
  1228.  
  1229. #define MAX_LINES 50
  1230.  
  1231. /*
  1232.  * This one is used by qsort in get_dir().
  1233.  */
  1234. static int pstrcmp(struct svalue p1, struct svalue p2)
  1235. {
  1236.     return strcmp(p1->u.string, p2->u.string);
  1237. }
  1238.  
  1239. /*
  1240.  * List files in directory. This function do same as standard list_files did,
  1241.  * but instead writing files right away to player this returns an array
  1242.  * containing those files. Actually most of code is copied from list_files()
  1243.  * function.
  1244.  * Differences with list_files:
  1245.  *
  1246.  *   - file_list("/w"); returns ({ "w" })
  1247.  *
  1248.  *   - file_list("/w/"); and file_list("/w/."); return contents of directory
  1249.  *     "/w"
  1250.  *
  1251.  *   - file_list("/");, file_list("."); and file_list("/."); return contents
  1252.  *     of directory "/"
  1253.  */
  1254. int list_files(char *path, int sflag)
  1255. {
  1256.     struct vector *v;
  1257.     int i, count = 0;
  1258.     int do_match = 0;
  1259.     int no_check = 0;
  1260.     DirList *dirList, *dlist;
  1261.     struct stat st;
  1262.     char *temppath;
  1263.     char *p;
  1264.     char *regexp = 0;
  1265.  
  1266.     if (!path) return 0;
  1267.  
  1268. #ifdef COMPAT_MODE
  1269.     path = check_file_name(path, 0);
  1270. #else
  1271.     path = check_valid_path(path, current_object->eff_user, "get_dir", 0);
  1272. #endif
  1273.  
  1274.     if (path == 0) return 0;
  1275.  
  1276.     /*
  1277.      * We need to modify the returned path, and thus to make a
  1278.      * writeable copy.
  1279.      * The path "" needs 2 bytes to store ".\0".
  1280.        */
  1281.     temppath = (char *)alloca(strlen(path)+2);
  1282.     if (strlen(path)<2) {
  1283.         temppath[0]=path[0]?path[0]:'.';
  1284.         temppath[1]='\000';
  1285.         p = temppath;
  1286.         no_check = 1;
  1287.     } else {
  1288.         strcpy(temppath, path);
  1289.         /*
  1290.          * If path ends with '/' or "/." remove it
  1291.          */
  1292.         if ((p = strrchr(temppath, '/')) == 0)
  1293.             p = temppath;
  1294.         if (p[0] == '/' && p[1] == '.' && p[2] == '\0' || 
  1295.             p[0] == '/' && p[1] == '\0')
  1296.             *p = '\0';
  1297.     }
  1298.  
  1299.     if (!no_check && stat(temppath, &st) < 0) {
  1300.         if (*p == '\0')
  1301.             return 0;
  1302.         regexp = (char *)alloca(strlen(p)+2);
  1303.         if (p != temppath) {
  1304.             strcpy(regexp, p + 1);
  1305.             *p = '\0';
  1306.         } else {
  1307.             strcpy(regexp, p);
  1308.             strcpy(temppath, ".");
  1309.         }
  1310.         do_match = 1;
  1311.     } else if (*p != '\0' && strcmp(temppath, ".")) {
  1312.     if (*p == '/' && *(p + 1) != '\0')
  1313.         p++;
  1314.     v = allocate_array(1);
  1315.     v->item[0].type = T_STRING;
  1316.     v->item[0].string_type = STRING_MALLOC;
  1317.     v->item[0].u.string = string_copy(p);
  1318.     return v;
  1319.     }
  1320.     dirList = macgetdir(temppath);
  1321.     for (dlist = dirList; dlist; dlist = dlist->next) {
  1322.         if (do_match && !match_string(regexp, dlist->name)) {
  1323.             continue;
  1324.         }
  1325.         count++;
  1326.         if (count >= MAX_ARRAY_SIZE) {
  1327.             break;
  1328.         }
  1329.     }
  1330.     /*
  1331.      * Make array and put files on it.
  1332.      */
  1333.     v = allocate_array(count);
  1334.     for (i = 0, dlist = dirList; count && dlist; dlist = dlist->next, i++) {
  1335.         if (do_match && !match_string(regexp, dlist->name))
  1336.             continue;
  1337.         v->item[i].type = T_STRING;
  1338.         v->item[i].string_type = STRING_MALLOC;
  1339.         v->item[i].u.string = dlist->name;
  1340.     }
  1341.     macfreedir(dirList);
  1342.     /* Sort the names. */
  1343.     qsort((char *)v->item, count, sizeof v->item[0], pstrcmp);
  1344.  
  1345.     for (i = 0; i < count; i++) {
  1346.         add_message("%s",v->item[i].u.string);
  1347.     }
  1348.  
  1349.     return 1;
  1350. }
  1351.  
  1352. /*
  1353.  * List files in directory. This function do same as standard list_files did,
  1354.  * but instead writing files right away to player this returns an array
  1355.  * containing those files. Actually most of code is copied from list_files()
  1356.  * function.
  1357.  * Differences with list_files:
  1358.  *
  1359.  *   - file_list("/w"); returns ({ "w" })
  1360.  *
  1361.  *   - file_list("/w/"); and file_list("/w/."); return contents of directory
  1362.  *     "/w"
  1363.  *
  1364.  *   - file_list("/");, file_list("."); and file_list("/."); return contents
  1365.  *     of directory "/"
  1366.  */
  1367. struct vector *get_dir(char *path)
  1368. {
  1369.     struct vector *v;
  1370.     int i, count = 0;
  1371.     int do_match = 0;
  1372.     int no_check = 0;
  1373.     DirList *dirList, *dlist;
  1374.     struct stat st;
  1375.     char *temppath;
  1376.     char *p;
  1377.     char *regexp = 0;
  1378.  
  1379.     if (!path)
  1380.     return 0;
  1381.  
  1382. #ifdef COMPAT_MODE
  1383.     path = check_file_name(path, 0);
  1384. #else
  1385.     path = check_valid_path(path, current_object->eff_user, "get_dir", 0);
  1386. #endif
  1387.  
  1388.     if (path == 0)
  1389.     return 0;
  1390.  
  1391.     /*
  1392.      * We need to modify the returned path, and thus to make a
  1393.      * writeable copy.
  1394.      * The path "" needs 2 bytes to store ".\0".
  1395.      */
  1396.     temppath = (char *)alloca(strlen(path)+2);
  1397.     if (strlen(path)<2) {
  1398.     temppath[0]=path[0]?path[0]:'.';
  1399.     temppath[1]='\000';
  1400.     p = temppath;
  1401.     no_check = 1;
  1402.     } else {
  1403.     strcpy(temppath, path);
  1404.     /*
  1405.      * If path ends with '/' or "/." remove it
  1406.      */
  1407.     if ((p = strrchr(temppath, '/')) == 0)
  1408.         p = temppath;
  1409.     if (p[0] == '/' && p[1] == '.' && p[2] == '\0' || 
  1410.         p[0] == '/' && p[1] == '\0')
  1411.         *p = '\0';
  1412.     }
  1413.  
  1414.     if (no_check) {
  1415.     } else
  1416.     if (stat(temppath, &st) < 0) {
  1417.     if (*p == '\0')
  1418.         return 0;
  1419.     regexp = (char *)alloca(strlen(p)+2);
  1420.     if (p != temppath) {
  1421.         strcpy(regexp, p + 1);
  1422.         *p = '\0';
  1423.     } else {
  1424.         strcpy(regexp, p);
  1425.         strcpy(temppath, ".");
  1426.     }
  1427.     do_match = 1;
  1428.     } else if (*p != '\0' && strcmp(temppath, ".")) {
  1429.     if (*p == '/' && *(p + 1) != '\0')
  1430.         p++;
  1431.     v = allocate_array(1);
  1432.     v->item[0].type = T_STRING;
  1433.     v->item[0].string_type = STRING_MALLOC;
  1434.     v->item[0].u.string = string_copy(p);
  1435.     return v;
  1436.     }
  1437.     dirList = macgetdir(temppath);
  1438.     for (count = 0, dlist = dirList; dlist; dlist = dlist->next) {
  1439.         if (do_match && !match_string(regexp, dlist->name)) {
  1440.             continue;
  1441.         }
  1442.         count++;
  1443.         if (count >= MAX_ARRAY_SIZE) {
  1444.             break;
  1445.         }
  1446.     }
  1447.     /*
  1448.      * Make array and put files on it.
  1449.      */
  1450.     v = allocate_array(count);
  1451.     if (count == 0) {
  1452.         /* This is the easy case :-) */
  1453.         macfreedir(dirList);
  1454.         return v;
  1455.     }
  1456.     for (i = 0, dlist = dirList; dlist; dlist = dlist->next, i++) {
  1457.         if (do_match && !match_string(regexp, dlist->name))
  1458.             continue;
  1459.         v->item[i].type = T_STRING;
  1460.         v->item[i].string_type = STRING_MALLOC;
  1461.         v->item[i].u.string = dlist->name;
  1462.     }
  1463.     macfreedir(dirList);
  1464.     /* Sort the names. */
  1465.     qsort((char *)v->item, count, sizeof v->item[0], pstrcmp);
  1466.     return v;
  1467. }
  1468. #ifndef NLHACK
  1469. int tail(path)
  1470.     char *path;
  1471. {
  1472.     char buff[1000];
  1473.     FILE *f;
  1474.     struct stat st;
  1475.     int offset;
  1476.  
  1477. #ifdef COMPAT_MODE
  1478.     path = check_file_name(path, 0);
  1479. #else
  1480.     path = check_valid_path(path, current_object->eff_user, "tail", 0);
  1481. #endif
  1482.  
  1483.     if (path == 0)
  1484.         return 0;
  1485. #ifdef MSDOS
  1486.     dos_flush(1);
  1487. #endif
  1488.     f = fopen(path, "r");
  1489.     if (f == 0)
  1490.     return 0;
  1491. #ifndef mac
  1492.     if (fstat(fileno(f), &st) == -1)
  1493. #else
  1494.     if (stat(path, &st) == -1)
  1495. #endif
  1496.     fatal("Could not stat an open file.\n");
  1497.     offset = st.st_size - 54 * 20;
  1498.     if (offset < 0)
  1499.     offset = 0;
  1500.     if (fseek(f, offset, 0) == -1)
  1501.     fatal("Could not seek.\n");
  1502.     /* Throw away the first incomplete line. */
  1503.     if (offset > 0)
  1504.     (void)fgets(buff, sizeof buff, f);
  1505.     while(fgets(buff, sizeof buff, f)) {
  1506.     add_message("%s", buff);
  1507.     }
  1508.     fclose(f);
  1509.     return 1;
  1510. }
  1511. #endif
  1512. int print_file(path, start, len)
  1513.     char *path;
  1514.     int start, len;
  1515. {
  1516.     char buff[1000];
  1517.     FILE *f;
  1518.     int i;
  1519.  
  1520.     if (len < 0)
  1521.     return 0;
  1522.  
  1523. #ifdef COMPAT_MODE
  1524.     path = check_file_name(path, 0);
  1525. #else
  1526.     path = check_valid_path(path, current_object->eff_user, "print_file", 0);
  1527. #endif
  1528.  
  1529.     if (path == 0)
  1530.         return 0;
  1531.     if (start < 0)
  1532.     return 0;
  1533. #ifdef MSDOS
  1534.     dos_flush(1);
  1535. #endif
  1536.     f = fopen(path, "r");
  1537.     if (f == 0)
  1538.     return 0;
  1539.     if (len == 0)
  1540.     len = MAX_LINES;
  1541.     if (len > MAX_LINES)
  1542.     len = MAX_LINES;
  1543.     if (start == 0)
  1544.     start = 1;
  1545.     for (i=1; i < start + len; i++) {
  1546.     if (fgets(buff, sizeof buff, f) == 0)
  1547.         break;
  1548.     if (i >= start)
  1549.         add_message("%s", buff);
  1550.     }
  1551.     fclose(f);
  1552.     if (i <= start)
  1553.     return 0;
  1554.     if (i == MAX_LINES + start)
  1555.     add_message("*****TRUNCATED****\n");
  1556.     return i-start;
  1557. }
  1558. #ifndef NLHACK
  1559. int remove_file(path)
  1560.     char *path;
  1561. {
  1562. #ifdef COMPAT_MODE
  1563.     path = check_file_name(path, 1);
  1564. #else
  1565.     path = check_valid_path(path, current_object->eff_user, "remove_file", 1);
  1566. #endif
  1567.  
  1568.     if (path == 0)
  1569.         return 0;
  1570. #ifndef mac
  1571.     if (unlink(path) == -1)
  1572. #else
  1573.     if (macremove(path) == -1)
  1574. #endif
  1575.         return 0;
  1576.     return 1;
  1577. }
  1578. #endif
  1579. void log_file(file, str)
  1580.     char *file, *str;
  1581. {
  1582.     FILE *f;
  1583.     char file_name[100];
  1584.     struct stat st;
  1585.     long maxsize;
  1586. #ifdef NLHACK
  1587.     struct svalue *wizname;
  1588.     char *p;
  1589. #endif
  1590.  
  1591. #ifdef COMPAT_MODE
  1592.     if (strchr(file, '/') || file[0] == '.' || strlen(file) > 30
  1593. #ifndef MSDOS
  1594.     )
  1595. #else
  1596.     || !valid_msdos(file))
  1597. #endif
  1598.     error("Illegal file name to log_file(%s)\n", file);
  1599. #endif
  1600.  
  1601. #ifdef NLHACK
  1602.     /*
  1603.      * .rep files ---> ~/logs
  1604.      *  admin log files ---> /log/admin
  1605.      *  files in player objects ---> ~/logs
  1606.      *  files in capital letters ---> /log
  1607.      *  all the rest ---> /log
  1608.      *
  1609.      * This code is a bit messy, unfortunately.
  1610.      */
  1611.  
  1612.     if (log_admin_check(file)) {
  1613.     sprintf(file_name, "/log/admin/%s", file);
  1614.     maxsize = MAX_GLOBAL_LOG_SIZE;
  1615.     } else if ((p = strchr(file, '.')) && !strcmp(p, ".rep")) {
  1616.     *p = '\0';
  1617.     sprintf(file_name,"/%s/%s/logs/%s%s", PLAYER_DIR, file, file, ".rep");
  1618.     maxsize = MAX_LOCAL_LOG_SIZE;
  1619.     } else if (all_cap(file)) {
  1620.     sprintf(file_name,"/log/%s", file);
  1621.     maxsize = MAX_GLOBAL_LOG_SIZE;
  1622.     }
  1623.     else {
  1624.     push_constant_string(current_object->name);
  1625.     wizname = apply_master_ob("get_wiz_name", 1);
  1626.     if (!wizname || wizname->type != T_STRING) {
  1627.         sprintf(file_name, "/log/%s", file);
  1628.         maxsize = MAX_GLOBAL_LOG_SIZE;
  1629.     }
  1630.     else {
  1631.         sprintf(file_name, "/%s/%s/logs/%s", PLAYER_DIR, wizname->u.string,
  1632.         file);
  1633.         maxsize = MAX_LOCAL_LOG_SIZE;
  1634.     }
  1635.     }
  1636. #else
  1637.     sprintf(file_name, "/log/%s", file);
  1638.     maxsize = MAX_GLOBAL_LOG_SIZE;
  1639. #endif
  1640. #ifndef COMPAT_MODE
  1641.     if (!check_valid_path(file_name, current_object->eff_user, "log_file", 1))
  1642.         return;
  1643. #endif
  1644.     if (stat(file_name+1, &st) != -1 && st.st_size > maxsize) {
  1645.     char file_name2[sizeof file_name + 4];
  1646.     sprintf(file_name2, "%s.old", file_name+1);
  1647.     rename(file_name+1, file_name2);    /* No panic if failure */
  1648.     }
  1649.     f = fopen(file_name+1, "a");    /* Skip leading '/' */
  1650.     if (f == 0)
  1651.     return;
  1652.     fwrite(str, strlen(str), 1, f);
  1653.     fclose(f);
  1654. }
  1655.  
  1656. void
  1657. print_svalue(arg)
  1658.     struct svalue *arg;
  1659. {
  1660.     if (arg == 0)
  1661.     add_message("<NULL>");
  1662.     else if (arg->type == T_STRING) {
  1663.     if (strlen(arg->u.string) > 9500)    /* Not pretty */
  1664.         error("Too long string.\n");
  1665.     /* Strings sent to monsters are now delivered */
  1666.     if (command_giver && (command_giver->flags & O_ENABLE_COMMANDS) &&
  1667.               !command_giver->interactive)
  1668.         tell_npc(command_giver, arg->u.string);
  1669.     else
  1670.         add_message("%s", arg->u.string);
  1671.     } else if (arg->type == T_OBJECT)
  1672.     add_message("OBJ(%s)", arg->u.ob->name);
  1673.     else if (arg->type == T_NUMBER)
  1674.     add_message("%d", arg->u.number);
  1675.     else if (arg->type == T_POINTER)
  1676.     add_message("<ARRAY>");
  1677.     else if (arg->type == T_MAPPING)
  1678.     add_message("<MAPPING>");
  1679.     else
  1680.     add_message("<UNKNOWN>");
  1681. }
  1682.  
  1683. void do_write(arg)
  1684.     struct svalue *arg;
  1685. {
  1686.     struct object *save_command_giver = command_giver;
  1687.     if (command_giver == 0 && current_object->shadowing)
  1688.     command_giver = current_object;
  1689.     if (command_giver) {
  1690.     /* Send the message to the first object in the shadow list */
  1691.     while (command_giver->shadowing)
  1692.         command_giver = command_giver->shadowing;
  1693.     }
  1694.     print_svalue(arg);
  1695.     command_giver = save_command_giver;
  1696. }
  1697.  
  1698. /* Find an object. If not loaded, load it !
  1699.  * The object may selfdestruct, which is the only case when 0 will be
  1700.  * returned.
  1701.  */
  1702.  
  1703. struct object *find_object(str)
  1704.     char *str;
  1705. {
  1706.     struct object *ob;
  1707.  
  1708.     /* Remove leading '/' if any. */
  1709.     while(str[0] == '/')
  1710.     str++;
  1711.     ob = find_object2(str);
  1712.     if (ob)
  1713.     return ob;
  1714.     ob = load_object(str, 0, 0);
  1715.     if (ob->flags & O_DESTRUCTED)        /* *sigh* */
  1716.     return 0;
  1717.     if (ob && ob->flags & O_SWAPPED)
  1718.     load_ob_from_swap(ob);
  1719.     return ob;
  1720. }
  1721.  
  1722. /* Look for a loaded object. Return 0 if non found. */
  1723. struct object *find_object2(str)
  1724.     char *str;
  1725. {
  1726.     register struct object *ob;
  1727.     register int length;
  1728.  
  1729.     /* Remove leading '/' if any. */
  1730.     while(str[0] == '/')
  1731.     str++;
  1732.     /* Truncate possible .c in the object name. */
  1733.     length = strlen(str);
  1734.     if (str[length-2] == '.' && str[length-1] == 'c') {
  1735.     /* A new writreable copy of the name is needed. */
  1736.     char *p;
  1737.     p = (char *)alloca(strlen(str)+1);
  1738.     strcpy(p, str);
  1739.     str = p;
  1740.     str[length-2] = '\0';
  1741.     }
  1742.     if (ob = lookup_object_hash(str)) {
  1743.     if (ob->flags & O_SWAPPED)
  1744.         load_ob_from_swap(ob);
  1745.     return ob;
  1746.     }
  1747.     return 0;
  1748. }
  1749.  
  1750. #if 0
  1751.  
  1752. void apply_command(com)
  1753.     char *com;
  1754. {
  1755.     struct value *ret;
  1756.  
  1757.     if (command_giver == 0)
  1758.     error("command_giver == 0 !\n");
  1759.     ret = apply(com, command_giver->super, 0);
  1760.     if (ret != 0) {
  1761.     add_message("Result:");
  1762.     if (ret->type == T_STRING)
  1763.         add_message("%s\n", ret->u.string);
  1764.     if (ret->type == T_NUMBER)
  1765.         add_message("%d\n", ret->u.number);
  1766.     } else {
  1767.     add_message("Error apply_command: function %s not found.\n", com);
  1768.     }
  1769. }
  1770. #endif /* 0 */
  1771.  
  1772. /*
  1773.  * Transfer an object.
  1774.  * The object has to be taken from one inventory list and added to another.
  1775.  * The main work is to update all command definitions, depending on what is
  1776.  * living or not. Note that all objects in the same inventory are affected.
  1777.  *
  1778.  * There are some boring compatibility to handle. When -o flag is specified,
  1779.  * several functions are called in some objects. This is dangerous, as
  1780.  * object might self-destruct when called.
  1781.  */
  1782. void move_object(item, dest)
  1783.     struct object *item, *dest;
  1784. {
  1785.     struct object **pp, *ob, *next_ob;
  1786.     struct object *save_cmd = command_giver;
  1787.  
  1788. #ifndef COMPAT_MODE
  1789.     if (item != current_object)
  1790.     error("Illegal to move other object than this_object()\n");
  1791. #endif
  1792.     /* Recursive moves are not allowed. */
  1793.     for (ob = dest; ob; ob = ob->super)
  1794.     if (ob == item)
  1795.         error("Can't move object inside itself.\n");
  1796.     if (item->shadowing)
  1797.     error("Can't move an object that is shadowing.\n");
  1798.  
  1799. #if 0 /* Not now /Lars */
  1800.     /*
  1801.      * Objects must have inherited std/object if they are to be allowed to
  1802.      * be moved.
  1803.      */
  1804. #ifndef COMPAT_MODE
  1805.     if (!(item->flags & O_APPROVED) ||
  1806.             !(dest->flags & O_APPROVED)) {
  1807.     error("Trying to move object where src or dest not inherit std/object\n");
  1808.     return;
  1809.     }
  1810. #endif    
  1811. #endif
  1812. #ifdef COMPAT_MODE
  1813.     /* This is only needed in -o mode. Otherwise, objects can only move
  1814.      * themselves.
  1815.      */
  1816.     dest->flags &= ~O_RESET_STATE;
  1817.     item->flags &= ~O_RESET_STATE;
  1818. #endif
  1819.     add_light(dest, item->total_light);
  1820.     if (item->super) {
  1821.     int okey = 0;
  1822.         
  1823.     if (item->flags & O_ENABLE_COMMANDS) {
  1824. #ifdef COMPAT_MODE
  1825.         command_giver = item;
  1826.         push_object(item);
  1827.         (void)apply("exit", item->super, 1);
  1828.         if (item->flags & O_DESTRUCTED || dest->flags & O_DESTRUCTED)
  1829.             return;    /* Give up */
  1830. #endif
  1831.         remove_sent(item->super, item);
  1832.     }
  1833.     if (item->super->flags & O_ENABLE_COMMANDS)
  1834.         remove_sent(item, item->super);
  1835.     add_light(item->super, - item->total_light);
  1836.     for (pp = &item->super->contains; *pp;) {
  1837.         if (*pp != item) {
  1838.         if ((*pp)->flags & O_ENABLE_COMMANDS)
  1839.             remove_sent(item, *pp);
  1840.         if (item->flags & O_ENABLE_COMMANDS)
  1841.             remove_sent(*pp, item);
  1842.         pp = &(*pp)->next_inv;
  1843.         continue;
  1844.         }
  1845.         *pp = item->next_inv;
  1846.         okey = 1;
  1847.     }
  1848.     if (!okey)
  1849.         fatal("Failed to find object %s in super list of %s.\n",
  1850.           item->name, item->super->name);
  1851.     }
  1852.     item->next_inv = dest->contains;
  1853.     dest->contains = item;
  1854.     item->super = dest;
  1855.     /*
  1856.      * Setup the new commands. The order is very important, as commands
  1857.      * in the room should override commands defined by the room.
  1858.      * Beware that init() in the room may have moved 'item' !
  1859.      *
  1860.      * The call of init() should really be done by the object itself
  1861.      * (except in the -o mode). It might be too slow, though :-(
  1862.      */
  1863.     if (item->flags & O_ENABLE_COMMANDS) {
  1864.     command_giver = item;
  1865.     (void)apply("init", dest, 0);
  1866.     if ((dest->flags & O_DESTRUCTED) || item->super != dest) {
  1867.         command_giver = save_cmd; /* marion */
  1868.         return;
  1869.     }
  1870.     }
  1871.     /*
  1872.      * Run init of the item once for every present player, and
  1873.      * for the environment (which can be a player).
  1874.      */
  1875.     for (ob = dest->contains; ob; ob=next_ob) {
  1876.     next_ob = ob->next_inv;
  1877.     if (ob == item)
  1878.         continue;
  1879.     if (ob->flags & O_DESTRUCTED)
  1880.         error("An object was destructed at call of init()\n");
  1881.     if (ob->flags & O_ENABLE_COMMANDS) {
  1882.         command_giver = ob;
  1883.         (void)apply("init", item, 0);
  1884.         if (dest != item->super) {
  1885.         command_giver = save_cmd; /* marion */
  1886.         return;
  1887.         }
  1888.     }
  1889.     if (item->flags & O_DESTRUCTED) /* marion */
  1890.         error("The object to be moved was destructed at call of init()\n");
  1891.     if (item->flags & O_ENABLE_COMMANDS) {
  1892.         command_giver = item;
  1893.         (void)apply("init", ob, 0);
  1894.         if (dest != item->super) {
  1895.         command_giver = save_cmd; /* marion */
  1896.         return;
  1897.         }
  1898.     }
  1899.     }
  1900.     if (dest->flags & O_DESTRUCTED) /* marion */
  1901.     error("The destination to move to was destructed at call of init()\n");
  1902.     if (dest->flags & O_ENABLE_COMMANDS) {
  1903.     command_giver = dest;
  1904.     (void)apply("init", item, 0);
  1905.     }
  1906.     command_giver = save_cmd;
  1907. }
  1908.  
  1909. /*
  1910.  * Every object as a count of number of light sources it contains.
  1911.  * Update this.
  1912.  */
  1913.  
  1914. void add_light(p, n)
  1915.     struct object *p;
  1916.     int n;
  1917. {
  1918.     if (n == 0)
  1919.     return;
  1920.     p->total_light += n;
  1921.     if (p->super)
  1922.     add_light(p->super, n);
  1923. }
  1924.  
  1925. struct sentence *sent_free = 0;
  1926. int tot_alloc_sentence;
  1927.  
  1928. struct sentence *alloc_sentence() {
  1929.     struct sentence *p;
  1930.  
  1931.     if (sent_free == 0) {
  1932.     p = (struct sentence *)xalloc(sizeof *p);
  1933.     tot_alloc_sentence++;
  1934.     } else {
  1935.     p = sent_free;
  1936.     sent_free = sent_free->next;
  1937.     }
  1938.     p->verb = 0;
  1939.     p->function = 0;
  1940.     p->next = 0;
  1941.     return p;
  1942. }
  1943.  
  1944. #ifdef free
  1945. void free_all_sent() {
  1946.     struct sentence *p;
  1947.     for (;sent_free; sent_free = p) {
  1948.     p = sent_free->next;
  1949.     xfree(sent_free);
  1950.     }
  1951. }
  1952. #endif
  1953.  
  1954. void free_sentence(p)
  1955.     struct sentence *p;
  1956. {
  1957.     if (p->function)
  1958.     free_string(p->function);
  1959.     p->function = 0;
  1960.     if (p->verb)
  1961.     free_string(p->verb);
  1962.     p->verb = 0;
  1963.     p->next = sent_free;
  1964.     sent_free = p;
  1965. }
  1966.  
  1967. /*
  1968.  * Find the sentence for a command from the player.
  1969.  * Return success status.
  1970.  */
  1971. int player_parser(buff)
  1972.     char *buff;
  1973. {
  1974.     struct sentence *s;
  1975.     char *p;
  1976.     int length;
  1977.     struct object *save_current_object = current_object;
  1978.     char verb_copy[100];
  1979.  
  1980.     if (d_flag > 1)
  1981.     debug_message("cmd [%s]: %s\n", command_giver->name, buff);
  1982.     /* strip trailing spaces. */
  1983.     for (p = buff + strlen(buff) - 1; p >= buff; p--) {
  1984.     if (*p != ' ')
  1985.         break;
  1986.     *p = '\0';
  1987.     }
  1988.     if (buff[0] == '\0')
  1989.     return 0;
  1990.     if (special_parse(buff))
  1991.     return 1;
  1992.     p = strchr(buff, ' ');
  1993.     if (p == 0)
  1994.     length = strlen(buff);
  1995.     else
  1996.     length = p - buff;
  1997.     clear_notify();
  1998.     for (s=command_giver->sent; s; s = s->next) {
  1999.     struct svalue *ret;
  2000.     int len;
  2001.     struct object *command_object;
  2002.     
  2003.     if (s->verb == 0)
  2004.         error("An 'action' did something, but returned 0 or had an undefined verb.\n");
  2005.     len = strlen(s->verb);
  2006.     if (s->no_space) {
  2007.         if(strncmp(buff, s->verb,len) != 0)
  2008.         continue;
  2009.     } else if (s->short_verb) {
  2010.         if (strncmp(s->verb, buff, len) != 0)
  2011.         continue;
  2012.     } else {
  2013.         if (len != length) continue;
  2014.         if (strncmp(buff, s->verb, length))
  2015.         continue;
  2016.     }
  2017.     /*
  2018.      * Now we have found a special sentence !
  2019.      */
  2020.     if (d_flag > 1)
  2021.         debug_message("Local command %s on %s\n", s->function, s->ob->name);
  2022.     if (length >= sizeof verb_copy)
  2023.         len = sizeof verb_copy - 1;
  2024.     else
  2025.         len = length;
  2026.     strncpy(verb_copy, buff, len);
  2027.     verb_copy[len] = '\0';
  2028.     last_verb = verb_copy;
  2029.     /*
  2030.      * If the function is static and not defined by current object,
  2031.      * then it will fail. If this is called directly from player input,
  2032.      * then we set current_object so that static functions are allowed.
  2033.      * current_object is reset just after the call to apply().
  2034.      */
  2035.     if (current_object == 0)
  2036.         current_object = s->ob;
  2037.     /*
  2038.      * Remember the object, to update score.
  2039.      */
  2040.     command_object = s->ob;
  2041.     if(s->no_space) {
  2042.         push_constant_string(&buff[strlen(s->verb)]);
  2043.         ret = apply(s->function,s->ob, 1);
  2044.     } else if (buff[length] == ' ') {
  2045.         push_constant_string(&buff[length+1]);
  2046.         ret = apply(s->function, s->ob, 1);
  2047.     } else {
  2048.         ret = apply(s->function, s->ob, 0);
  2049.     }
  2050.     if (current_object->flags & O_DESTRUCTED) {
  2051.         /* If disable_commands() were called, then there is no
  2052.          * command_giver any longer.
  2053.          */
  2054.         if (command_giver == 0)
  2055.         return 1;
  2056.         s = command_giver->sent;    /* Restart :-( */
  2057.     }
  2058.     current_object = save_current_object;
  2059.     last_verb = 0;
  2060.     /* If we get fail from the call, it was wrong second argument. */
  2061.     if (ret && ret->type == T_NUMBER && ret->u.number == 0)
  2062.         continue;
  2063.     if (s && command_object->user && command_giver->interactive &&
  2064.         !(command_giver->flags & O_IS_WIZARD))
  2065.     {
  2066.         command_object->user->score++;
  2067.     }
  2068.     if (ret == 0)
  2069.         add_message("Error: function %s not found.\n", s->function);
  2070.     break;
  2071.     }
  2072.     if (s == 0) {
  2073.     notify_no_command();
  2074.     return 0;
  2075.     }
  2076.     return 1;
  2077. }
  2078.  
  2079. /*
  2080.  * Associate a command with function in this object.
  2081.  * The optional second argument is the command name. If the command name
  2082.  * is not given here, it should be given with add_verb().
  2083.  *
  2084.  * The optinal third argument is a flag that will state that the verb should
  2085.  * only match against leading characters.
  2086.  *
  2087.  * The object must be near the command giver, so that we ensure that the
  2088.  * sentence is removed when the command giver leaves.
  2089.  *
  2090.  * If the call is from a shadow, make it look like it is really from
  2091.  * the shadowed object.
  2092.  */
  2093. void add_action(str, cmd, flag)
  2094.     char *str, *cmd;
  2095.     int flag;
  2096. {
  2097.     struct sentence *p;
  2098.     struct object *ob;
  2099.  
  2100.     if (str[0] == ':')
  2101.     error("Illegal function name: %s\n", str);
  2102.     if (current_object->flags & O_DESTRUCTED)
  2103.     return;
  2104.     ob = current_object;
  2105.     while(ob->shadowing)
  2106.     ob = ob->shadowing;
  2107.     if (command_giver == 0 || (command_giver->flags & O_DESTRUCTED))
  2108.     return;
  2109.     if (ob != command_giver && ob->super != command_giver &&
  2110.     ob->super != command_giver->super && ob != command_giver->super)
  2111.       error("add_action from object that was not present.\n");
  2112.     if (d_flag > 1)
  2113.     debug_message("--Add action %s\n", str);
  2114. #ifdef COMPAT_MODE
  2115.     if (strcmp(str, "exit") == 0)
  2116.     error("Illegal to define a command to the exit() function.\n");
  2117. #endif
  2118.     p = alloc_sentence();
  2119.     p->function = make_shared_string(str);
  2120.     p->ob = ob;
  2121.     p->next = command_giver->sent;
  2122.     p->short_verb = flag;
  2123.     p->no_space = 0;
  2124.     if (cmd)
  2125.     p->verb = make_shared_string(cmd);
  2126.     else
  2127.     p->verb = 0;
  2128.     command_giver->sent = p;
  2129. }
  2130.  
  2131. void add_verb(str, no_space)
  2132.     char *str;
  2133.     int no_space;
  2134. {
  2135.     if (command_giver == 0 || (command_giver->flags & O_DESTRUCTED))
  2136.     return;
  2137.     if (command_giver->sent == 0)
  2138.     error("No add_action().\n");
  2139.     if (command_giver->sent->verb != 0)
  2140.     error("Tried to set verb again.\n");
  2141.     command_giver->sent->verb = make_shared_string(str);
  2142.     command_giver->sent->no_space = no_space;
  2143.     if (d_flag > 1)
  2144.     debug_message("--Adding verb %s to action %s\n", str,
  2145.         command_giver->sent->function);
  2146. }
  2147.  
  2148. /*
  2149.  * Remove all commands (sentences) defined by object 'ob' in object
  2150.  * 'player'
  2151.  */
  2152. void remove_sent(ob, player)
  2153.     struct object *ob, *player;
  2154. {
  2155.     struct sentence **s;
  2156.  
  2157.     for (s= &player->sent; *s;) {
  2158.     struct sentence *tmp;
  2159.     if ((*s)->ob == ob) {
  2160.         if (d_flag > 1)
  2161.         debug_message("--Unlinking sentence %s\n", (*s)->function);
  2162.         tmp = *s;
  2163.         *s = tmp->next;
  2164.         free_sentence(tmp);
  2165.     } else
  2166.         s = &((*s)->next);
  2167.     }
  2168. }
  2169.  
  2170. char debug_parse_buff[50]; /* Used for debugging */
  2171.  
  2172. /*
  2173.  * Hard coded commands, that will be available to all players. They can not
  2174.  * be redefined, so the command name should be something obscure, not likely
  2175.  * to be used in the game.
  2176.  */
  2177. int special_parse(buff)
  2178.     char *buff;
  2179. {
  2180. #ifdef DEBUG
  2181.     strncpy(debug_parse_buff, buff, sizeof debug_parse_buff);
  2182.     debug_parse_buff[sizeof debug_parse_buff - 1] = '\0';
  2183. #endif
  2184.     if (strcmp(buff, "malloc") == 0) {
  2185. #if defined(MALLOC_malloc) || defined(MALLOC_smalloc)
  2186.     dump_malloc_data();
  2187. #endif
  2188. #ifdef MALLOC_gmalloc
  2189.     add_message("Using Gnu malloc.\n");
  2190. #endif
  2191. #ifdef MALLOC_sysmalloc
  2192.     add_message("Usage system standard malloc.\n");
  2193. #endif
  2194.     return 1;
  2195.     }
  2196.     if (strcmp(buff, "dumpallobj") == 0) {
  2197.         dumpstat();
  2198.     return 1;
  2199.     }
  2200. #if defined(MALLOC_malloc) || defined(MALLOC_smalloc)
  2201.     if (strcmp(buff, "debugmalloc") == 0) {
  2202.     extern int debugmalloc;
  2203.     debugmalloc = !debugmalloc;
  2204.     if (debugmalloc)
  2205.         add_message("On.\n");
  2206.     else
  2207.         add_message("Off.\n");
  2208.     return 1;
  2209.     }
  2210. #endif
  2211.     if (strcmp(buff, "status") == 0 || strcmp(buff, "status tables") == 0) {
  2212.     int tot, res, verbose = 0;
  2213.     extern char *reserved_area;
  2214.     extern int tot_alloc_sentence, tot_alloc_object,
  2215.         tot_alloc_object_size, num_swapped, total_bytes_swapped,
  2216.         num_arrays, total_array_size;
  2217.     extern int total_num_prog_blocks, total_prog_block_size;
  2218. #ifdef COMM_STAT
  2219.     extern int add_message_calls,inet_packets,inet_volume;
  2220. #endif
  2221.  
  2222.     if (strcmp(buff, "status tables") == 0)
  2223.         verbose = 1;
  2224.     if (reserved_area)
  2225.         res = RESERVED_SIZE;
  2226.     else
  2227.         res = 0;
  2228. #ifdef COMM_STAT
  2229.     if (verbose)
  2230.         add_message("Calls to add_message: %d   Packets: %d   Average packet size: %f\n\n",add_message_calls,inet_packets,(float)inet_volume/inet_packets);
  2231. #endif
  2232.     if (!verbose) {
  2233.         add_message("Sentences:\t\t\t%8d %8d\n", tot_alloc_sentence,
  2234.             tot_alloc_sentence * sizeof (struct sentence));
  2235.         add_message("Objects:\t\t\t%8d %8d\n",
  2236.             tot_alloc_object, tot_alloc_object_size);
  2237.         add_message("Arrays:\t\t\t\t%8d %8d\n", num_arrays,
  2238.             total_array_size);
  2239.         add_message("Prog blocks:\t\t\t%8d %8d (%d swapped, %d Kbytes)\n",
  2240.             total_num_prog_blocks, total_prog_block_size,
  2241.             num_swapped, total_bytes_swapped / 1024);
  2242.         add_message("Memory reserved:\t\t\t %8d\n", res);
  2243.     }
  2244.     if (verbose)
  2245.         stat_living_objects();
  2246.     tot =           total_prog_block_size +
  2247.                total_array_size +
  2248.                tot_alloc_object_size +
  2249.                show_otable_status(verbose) +
  2250.                heart_beat_status(verbose) +
  2251.                add_string_status(verbose) +
  2252.                print_call_out_usage(verbose) +
  2253.                res;
  2254.  
  2255.     if (!verbose) {
  2256.         add_message("\t\t\t\t\t --------\n");
  2257.         add_message("Total:\t\t\t\t\t %8d\n", tot);
  2258.     }
  2259.     return 1;
  2260.     }
  2261.     if (strcmp(buff, "e") == 0) {
  2262.     (void)strcpy(buff, "east");
  2263.     return 0;
  2264.     }
  2265.     if (strcmp(buff, "w") == 0) {
  2266.     (void)strcpy(buff, "west");
  2267.     return 0;
  2268.     }
  2269.     if (strcmp(buff, "s") == 0) {
  2270.     (void)strcpy(buff, "south");
  2271.     return 0;
  2272.     }
  2273.     if (strcmp(buff, "n") == 0) {
  2274.     (void)strcpy(buff, "north");
  2275.     return 0;
  2276.     }
  2277.     if (strcmp(buff, "d") == 0) {
  2278.     (void)strcpy(buff, "down");
  2279.     return 0;
  2280.     }
  2281.     if (strcmp(buff, "u") == 0) {
  2282.     (void)strcpy(buff, "up");
  2283.     return 0;
  2284.     }
  2285.     if (strcmp(buff, "nw") == 0) {
  2286.     (void)strcpy(buff, "northwest");
  2287.     return 0;
  2288.     }
  2289.     if (strcmp(buff, "ne") == 0) {
  2290.     (void)strcpy(buff, "northeast");
  2291.     return 0;
  2292.     }
  2293.     if (strcmp(buff, "sw") == 0) {
  2294.     (void)strcpy(buff, "southwest");
  2295.     return 0;
  2296.     }
  2297.     if (strcmp(buff, "se") == 0) {
  2298.     (void)strcpy(buff, "southeast");
  2299.     return 0;
  2300.     }
  2301.     return 0;
  2302. }
  2303.  
  2304. void print_local_commands() {
  2305.     struct sentence *s;
  2306.  
  2307.     add_message("Current local commands:\n");
  2308.     for (s = command_giver->sent; s; s = s->next)
  2309.     add_message("%s ", s->verb);
  2310.     add_message("\n");
  2311. }
  2312.  
  2313. /*VARARGS1*/
  2314. void fatal(fmt, a, b, c, d, e, f, g, h)
  2315.     char *fmt;
  2316.     int a, b, c, d, e, f, g, h;
  2317. {
  2318.     static int in_fatal = 0;
  2319.     /* Prevent double fatal. */
  2320.     if (in_fatal)
  2321.     abort();
  2322.     in_fatal = 1;
  2323.     (void)fprintf(stderr, fmt, a, b, c, d, e, f, g, h);
  2324.     fflush(stderr);
  2325.     if (current_object)
  2326.     (void)fprintf(stderr, "Current object was %s\n",
  2327.               current_object->name);
  2328.     debug_message(fmt, a, b, c, d, e, f, g, h);
  2329.     if (current_object)
  2330.     debug_message("Current object was %s\n", current_object->name);
  2331.     debug_message("Dump of variables:\n");
  2332.     (void)dump_trace(1);
  2333.     abort();
  2334. }
  2335.  
  2336. int num_error = 0;
  2337.  
  2338. /*
  2339.  * Error() has been "fixed" so that users can catch and throw them.
  2340.  * To catch them nicely, we really have to provide decent error information.
  2341.  * Hence, all errors that are to be caught
  2342.  * (error_recovery_context_exists == 2) construct a string containing
  2343.  * the error message, which is returned as the
  2344.  * thrown value.  Users can throw their own error values however they choose.
  2345.  */
  2346.  
  2347. /*
  2348.  * This is here because throw constructs its own return value; we dont
  2349.  * want to replace it with the system's error string.
  2350.  */
  2351.  
  2352. void throw_error() {
  2353.     extern int error_recovery_context_exists;
  2354.     extern jmp_buf error_recovery_context;
  2355.     if (error_recovery_context_exists > 1) {
  2356.     longjmp(error_recovery_context, 1);
  2357.     fatal("Throw_error failed!");
  2358.     }
  2359.     error("Throw with no catch.\n");
  2360. }
  2361.  
  2362. static char emsg_buf[2000];
  2363.  
  2364. /*VARARGS1*/
  2365. void error(fmt, a, b, c, d, e, f, g, h)
  2366.     char *fmt;
  2367.     int a, b, c, d, e, f, g, h;
  2368. {
  2369.     extern int error_recovery_context_exists;
  2370.     extern jmp_buf error_recovery_context;
  2371.     extern struct object *current_heart_beat;
  2372.     extern struct svalue catch_value;
  2373.     char *object_name;
  2374.  
  2375.     sprintf(emsg_buf+1, fmt, a, b, c, d, e, f, g, h);
  2376.     emsg_buf[0] = '*';    /* all system errors get a * at the start */
  2377.     if (error_recovery_context_exists > 1) { /* user catches this error */
  2378.     struct svalue v;
  2379.     v.type = T_STRING;
  2380.     v.u.string = emsg_buf;
  2381.     v.string_type = STRING_MALLOC;    /* Always reallocate */
  2382.     assign_svalue(&catch_value, &v);
  2383.        longjmp(error_recovery_context, 1);
  2384.        fatal("Catch() longjump failed");
  2385.     }
  2386.     num_error++;
  2387.     if (num_error > 1)
  2388.     fatal("Too many simultaneous errors.\n");
  2389.     debug_message("%s", emsg_buf+1);
  2390.     if (current_object) {
  2391.     debug_message("program: %s, object: %s line %d\n",
  2392.             current_prog ? current_prog->name : "",
  2393.             current_object->name,
  2394.             get_line_number_if_any());
  2395.     if (current_prog)
  2396.         save_error(emsg_buf, current_prog->name,
  2397.                get_line_number_if_any());
  2398.     }
  2399.     object_name = dump_trace(0);
  2400.     fflush(stdout);
  2401.     if (object_name) {
  2402.     struct object *ob;
  2403.     ob = find_object2(object_name);
  2404.     if (!ob) {
  2405.         if (command_giver)
  2406.         add_message("error when executing program in destroyed object %s\n",
  2407.                 object_name);
  2408.         debug_message("error when executing program in destroyed object %s\n",
  2409.             object_name);
  2410.     }
  2411.     }
  2412.     if (command_giver && command_giver->interactive) {
  2413.     struct svalue *v = 0;
  2414.  
  2415.     num_error--;
  2416.     /* 
  2417.      * The stack must be brought in a usable state. After the
  2418.      * call to reset_machine(), all arguments to error() are invalid,
  2419.      * and may not be used any more. The reason is that some strings
  2420.      * may have been on the stack machine stack, and has been deallocated.
  2421.      */
  2422.     reset_machine (0);
  2423.     push_constant_string("error messages");
  2424.     v = apply_master_ob("query_player_level", 1);
  2425.     num_error++;
  2426.     if (v && v->u.number != 0) {
  2427.         add_message("%s", emsg_buf+1);
  2428.         if (current_object)
  2429.         add_message("program: %s, object: %s line %d\n",
  2430.                 current_prog ? current_prog->name : "",
  2431.                 current_object->name,
  2432.                 get_line_number_if_any());
  2433.     } else {
  2434.         add_message("Your sensitive mind notices a wrongness in the fabric of space.\n");
  2435.     }
  2436.     }
  2437.     if (current_heart_beat) {
  2438.     set_heart_beat(current_heart_beat, 0);
  2439.     debug_message("Heart beat in %s turned off.\n",
  2440.               current_heart_beat->name);
  2441.     if (current_heart_beat->interactive) {
  2442.         struct object *save_cmd = command_giver;
  2443.         command_giver = current_heart_beat;
  2444.         add_message("Game driver tells you: You have no heart beat !\n");
  2445.         command_giver = save_cmd;
  2446.     }
  2447.     current_heart_beat = 0;
  2448.     }
  2449.     num_error--;
  2450.     if (error_recovery_context_exists)
  2451.     longjmp(error_recovery_context, 1);
  2452.     abort();
  2453. }
  2454.  
  2455. /*
  2456.  * Check that it is an legal path. No '..' are allowed.
  2457.  */
  2458. int legal_path(path)
  2459.     char *path;
  2460. {
  2461.     char *p;
  2462.  
  2463.     if (path == NULL || strchr(path, ' '))
  2464.     return 0;
  2465.     if (path[0] == '/')
  2466.         return 0;
  2467. #ifdef MSDOS
  2468.     if (!valid_msdos(path)) return(0);
  2469. #endif
  2470.     for(p = strchr(path, '.'); p; p = strchr(p+1, '.')) {
  2471.     if (p[1] == '.')
  2472.         return 0;
  2473.     }
  2474.     return 1;
  2475. }
  2476.  
  2477. /*
  2478.  * There is an error in a specific file. Ask the game driver to log the
  2479.  * message somewhere.
  2480.  */
  2481. void smart_log(error_file, line, what)
  2482.      char *error_file, *what;
  2483.      int line;
  2484. {
  2485.     char buff[500];
  2486.  
  2487.     if (error_file == 0)
  2488.     return;
  2489.     if (strlen(what) + strlen(error_file) > sizeof buff - 100)
  2490.     what = "...[too long error message]...";
  2491.     if (strlen(what) + strlen(error_file) > sizeof buff - 100)
  2492.     error_file = "...[too long filename]...";
  2493.     sprintf(buff, "%s line %d:%s\n", error_file, line, what);
  2494.     push_constant_string(error_file);
  2495.     push_constant_string(buff);
  2496.     apply_master_ob("log_error", 2);
  2497. }
  2498.  
  2499. /*
  2500.  * Check that a file name is valid for read or write.
  2501.  * Also change the name as if the current directory was at the players
  2502.  * own directory.
  2503.  * This is done by functions in the player object.
  2504.  *
  2505.  * The master object (master.c) always have permissions to access
  2506.  * any file in the mudlib hierarchy, but only inside the mudlib.
  2507.  *
  2508.  * WARNING: The string returned will (mostly) be deallocated at next
  2509.  * call of apply().
  2510.  */
  2511. #ifdef COMPAT_MODE
  2512. char debug_check_file[50];
  2513.  
  2514. char *check_file_name(file, writeflg)
  2515.     char *file;
  2516.     int writeflg;
  2517. {
  2518.     struct svalue *ret;
  2519.     char *str;
  2520.  
  2521.     if (current_object && current_object->flags & O_DESTRUCTED)
  2522.     return 0;
  2523.     if (current_object != master_ob) {
  2524.     if (!command_giver || !command_giver->interactive ||
  2525.         (command_giver->flags & O_DESTRUCTED))
  2526.         return 0;
  2527.     push_constant_string(file);
  2528.     if (writeflg)
  2529.         ret = apply("valid_write", command_giver, 1);
  2530.     else
  2531.         ret = apply("valid_read",  command_giver, 1);
  2532.     if (command_giver->flags & O_DESTRUCTED)
  2533.         return 0;
  2534.     if (ret == 0 || ret->type != T_STRING) {
  2535.         add_message("Bad file name.\n");
  2536.         return 0;
  2537.     }
  2538.     str = ret->u.string;
  2539.     } else {
  2540.     /* Master object can read/write anywhere ! */
  2541.     if (file[0] == '/')
  2542.         str = file + 1;
  2543.     else
  2544.         str = file;
  2545.     }
  2546.     strncpy(debug_check_file, str, sizeof debug_check_file);
  2547.     debug_check_file[sizeof debug_check_file - 1] = '\0';
  2548.     if (!legal_path(str))
  2549.         error("Illegal path: %s\n", str);
  2550.     /* The string "/" will be converted to "". */
  2551.     if (str[0] == '\0')
  2552.     return ".";
  2553.     return str;
  2554. }
  2555. #endif /* COMPAT_MODE */
  2556.  
  2557. /*
  2558.  * Check that a path to a file is valid for read or write.
  2559.  * This is done by functions in the master object.
  2560.  * The path is always treated as an absolute path, and is returned without
  2561.  * a leading '/'.
  2562.  * If the path was '/', then '.' is returned.
  2563.  * The returned string may or may not be residing inside the argument 'path',
  2564.  * so don't deallocate arg 'path' until the returned result is used no longer.
  2565.  * Otherwise, the returned path is temporarily allocated by apply(), which
  2566.  * means it will be dealocated at next apply().
  2567.  */
  2568. char *check_valid_path(path, eff_user, call_fun, writeflg)
  2569.     char *path;
  2570.     struct wiz_list *eff_user;
  2571.     char *call_fun;
  2572.     int writeflg;
  2573. {
  2574.     struct svalue *v;
  2575.  
  2576.     if (eff_user == 0)
  2577.     return 0;
  2578.     push_string(path, STRING_MALLOC);
  2579.     push_string(eff_user->name, STRING_CONSTANT);
  2580.     push_string(call_fun, STRING_CONSTANT);
  2581.     if (writeflg)
  2582.     v = apply_master_ob("valid_write", 3);
  2583.     else
  2584.     v = apply_master_ob("valid_read", 3);
  2585.     if (v && v->type == T_NUMBER && v->u.number == 0)
  2586.     return 0;
  2587.     if (path[0] == '/')
  2588.     path++;
  2589.     if (path[0] == '\0')
  2590.     path = ".";
  2591.     if (legal_path(path))
  2592.     return path;
  2593.     return 0;
  2594. }
  2595.  
  2596. /*
  2597.  * This one is called from HUP.
  2598.  */
  2599. int game_is_being_shut_down;
  2600.  
  2601. void startshutdowngame() {
  2602.     game_is_being_shut_down = 1;
  2603. }
  2604.  
  2605. /*
  2606.  * This one is called from the command "shutdown".
  2607.  * We don't call it directly from HUP, because it is dangerous when being
  2608.  * in an interrupt.
  2609.  */
  2610. void forceshutdowngame() {
  2611.     ipc_remove();
  2612.     remove_all_players();
  2613.     unlink_swap_file();
  2614.     remove_all_objects();
  2615. }
  2616.  
  2617. void shutdowngame() {
  2618.     shout_string("Game driver shouts: LPmud shutting down immediately.\n");
  2619.     save_wiz_file();
  2620.     forceshutdowngame();
  2621.     LPExit(0);
  2622. }
  2623.  
  2624. /*
  2625.  * Transfer an object from an object to an object.
  2626.  * Call add_weight(), drop(), get(), prevent_insert(), add_weight(),
  2627.  * and can_put_and_get() where needed.
  2628.  * Return 0 on success, and special code on failure:
  2629.  *
  2630.  * 1: To heavy for destination.
  2631.  * 2: Can't be dropped.
  2632.  * 3: Can't take it out of it's container.
  2633.  * 4: The object can't be inserted into bags etc.
  2634.  * 5: The destination doesn't allow insertions of objects.
  2635.  * 6: The object can't be picked up.
  2636.  */
  2637. #ifdef F_TRANSFER
  2638. int transfer_object(ob, to)
  2639.     struct object *ob, *to;
  2640. {
  2641.     struct svalue *v_weight, *ret;
  2642.     int weight;
  2643.     struct object *from = ob->super;
  2644.  
  2645.     /*
  2646.      * Get the weight of the object
  2647.      */
  2648. #ifndef COMPAT_MODE
  2649.     error("transfer() not allowed.\n");
  2650. #endif
  2651.     weight = 0;
  2652.     v_weight = apply("query_weight", ob, 0);
  2653.     if (v_weight && v_weight->type == T_NUMBER)
  2654.     weight = v_weight->u.number;
  2655.     if (ob->flags & O_DESTRUCTED)
  2656.     return 3;
  2657.     /*
  2658.      * If the original place of the object is a living object,
  2659.      * then we must call drop() to check that the object can be dropped.
  2660.      */
  2661.     if (from && (from->flags & O_ENABLE_COMMANDS)) {
  2662.     ret = apply("drop", ob, 0);
  2663.     if (ret && (ret->type != T_NUMBER || ret->u.number != 0))
  2664.         return 2;
  2665.     /* This shold not happen, but we can not trust LPC hackers. :-) */
  2666.     if (ob->flags & O_DESTRUCTED)
  2667.         return 2;
  2668.     }
  2669.     /*
  2670.      * If 'from' is not a room and not a player, check that we may
  2671.      * remove things out of it.
  2672.      */
  2673.     if (from && from->super && !(from->flags & O_ENABLE_COMMANDS)) {
  2674.     ret = apply("can_put_and_get", from, 0);
  2675.     if (!ret || (ret->type != T_NUMBER || ret->u.number == 0) ||
  2676.       (from->flags & O_DESTRUCTED))
  2677.         return 3;
  2678.     }
  2679.     /*
  2680.      * If the destination is not a room, and not a player,
  2681.      * Then we must test 'prevent_insert', and 'can_put_and_get'.
  2682.      */
  2683.     if (to->super && !(to->flags & O_ENABLE_COMMANDS)) {
  2684.     ret = apply("prevent_insert", ob, 0);
  2685.     if (ret && (ret->type != T_NUMBER || ret->u.number != 0))
  2686.         return 4;
  2687.     ret = apply("can_put_and_get", to, 0);
  2688.     if (!ret || (ret->type != T_NUMBER || ret->u.number == 0) ||
  2689.       (to->flags & O_DESTRUCTED) || (ob->flags & O_DESTRUCTED))
  2690.         return 5;
  2691.     }
  2692.     /*
  2693.      * If the destination is a player, check that he can pick it up.
  2694.      */
  2695.     if (to->flags & O_ENABLE_COMMANDS) {
  2696.     ret = apply("get", ob, 0);
  2697.     if (!ret || (ret->type == T_NUMBER && ret->u.number == 0) ||
  2698.       (ob->flags & O_DESTRUCTED))
  2699.         return 6;
  2700.     }
  2701.     /*
  2702.      * If it is not a room, correct the total weight in the destination.
  2703.      */
  2704.     if (to->super && weight) {
  2705.     /*
  2706.      * Check if the destination can carry that much.
  2707.      */
  2708.     push_number(weight);
  2709.     ret = apply("add_weight", to, 1);
  2710.     if (ret && ret->type == T_NUMBER && ret->u.number == 0)
  2711.         return 1;
  2712.     if (to->flags & O_DESTRUCTED)
  2713.         return 1;
  2714.     }
  2715.     /*
  2716.      * If it is not a room, correct the weight in the 'from' object.
  2717.      */
  2718.     if (from && from->super && weight) {
  2719.     push_number(-weight);
  2720.     (void)apply("add_weight", from, 1);
  2721.     }
  2722.     move_object(ob, to);
  2723.     return 0;
  2724. }
  2725. #endif /* F_TRANSFER */
  2726.  
  2727. /*
  2728.  * Move or destruct one object.
  2729.  */
  2730. void move_or_destruct(what, to)
  2731.     struct object *what, *to;
  2732. {
  2733.     struct svalue v;
  2734.  
  2735. #ifdef COMPAT_MODE
  2736.     int res;
  2737.     res = transfer_object(what, to);
  2738.     if (res == 0 || (what->flags & O_DESTRUCTED))
  2739.     return;
  2740.     if (res == 1 || res == 4 || res == 5) {
  2741.     if (to->super) {
  2742.         move_or_destruct(what, to->super);
  2743.         return;
  2744.     }
  2745.     }
  2746. #else
  2747.     struct svalue *svp;
  2748.     /* This is very dubious, why not just destruct them /JnA 
  2749.         */
  2750.     push_object(to);
  2751.     push_number(1);
  2752.     svp = apply("move", what, 2);
  2753.     if (svp && svp->type == T_NUMBER && svp->u.number == 0)
  2754.     return;
  2755.     if (what->flags & O_DESTRUCTED)
  2756.     return;
  2757. #endif
  2758.     
  2759.     /*
  2760.      * Failed to move the object. Then, it is destroyed.
  2761.      */
  2762.     v.type = T_OBJECT;
  2763.     v.u.ob = what;
  2764.     destruct_object(&v);
  2765. }
  2766.  
  2767. /*
  2768.  * Call this one when there is only little memory left. It will start
  2769.  * Armageddon.
  2770.  */
  2771. void slow_shut_down(minutes)
  2772.     int minutes;
  2773. {
  2774.     struct object *ob;
  2775.  
  2776.     /*
  2777.      * Swap out objects, and free some memory.
  2778.      */
  2779.     ob = find_object("obj/shut");
  2780.     if (!ob) {
  2781.     struct object *save_current = current_object,
  2782.                   *save_command = command_giver;
  2783.     command_giver = 0;
  2784.     current_object = 0;
  2785.     shout_string("Game driver shouts: Out of memory.\n");
  2786.     command_giver = save_command;
  2787.     current_object = save_current;
  2788. #ifndef _AIX
  2789.         startshutdowngame();
  2790. #else
  2791.         startshutdowngame(1);
  2792. #endif
  2793.     return;
  2794.     }
  2795.     shout_string("Game driver shouts: The memory is getting low !\n");
  2796.     push_number(minutes);
  2797.     (void)apply("shut", ob, 1);
  2798. }
  2799.  
  2800. int match_string(match, str)
  2801.     char *match, *str;
  2802. {
  2803.     int i;
  2804.  
  2805.  again:
  2806.     if (*str == '\0' && *match == '\0')
  2807.     return 1;
  2808.     switch(*match) {
  2809.     case '?':
  2810.     if (*str == '\0')
  2811.         return 0;
  2812.     str++;
  2813.     match++;
  2814.     goto again;
  2815.     case '*':
  2816.     match++;
  2817.     if (*match == '\0')
  2818.         return 1;
  2819.     for (i=0; str[i] != '\0'; i++)
  2820.         if (match_string(match, str+i))
  2821.         return 1;
  2822.     return 0;
  2823.     case '\0':
  2824.     return 0;
  2825.     case '\\':
  2826.     match++;
  2827.     if (*match == '\0')
  2828.         return 0;
  2829.     /* Fall through ! */
  2830.     default:
  2831.     if (*match == *str) {
  2832.         match++;
  2833.         str++;
  2834.         goto again;
  2835.     }
  2836.     return 0;
  2837.     }
  2838. }
  2839.  
  2840. /*
  2841.  * Credits for some of the code below goes to Free Software Foundation
  2842.  * Copyright (C) 1990 Free Software Foundation, Inc.
  2843.  * See the GNU General Public License for more details.
  2844.  */
  2845. #ifndef S_ISDIR
  2846. #define    S_ISDIR(m)    (((m)&S_IFMT) == S_IFDIR)
  2847. #endif
  2848.  
  2849. #ifndef S_ISREG
  2850. #define    S_ISREG(m)    (((m)&S_IFMT) == S_IFREG)
  2851. #endif
  2852.  
  2853. int
  2854. isdir (path)
  2855.      char *path;
  2856. {
  2857.   struct stat stats;
  2858.  
  2859.   return stat (path, &stats) == 0 && S_ISDIR (stats.st_mode);
  2860. }
  2861.  
  2862. void
  2863. strip_trailing_slashes (path)
  2864.      char *path;
  2865. {
  2866.   int last;
  2867.  
  2868.   last = strlen (path) - 1;
  2869.   while (last > 0 && path[last] == '/')
  2870.     path[last--] = '\0';
  2871. }
  2872.  
  2873. struct stat to_stats, from_stats;
  2874.  
  2875. int
  2876. copy (from, to)
  2877.      char *from, *to;
  2878. {
  2879.   int ifd;
  2880.   int ofd;
  2881.   char buf[1024 * 8];
  2882.   int len;            /* Number of bytes read into `buf'. */
  2883.   
  2884. #ifndef mac
  2885.   if (!S_ISREG (from_stats.st_mode))
  2886.     {
  2887.       error ("cannot move `%s' across filesystems: Not a regular file\n", from);
  2888.       return 1;
  2889.     }
  2890. #endif
  2891.   
  2892. #ifndef mac
  2893.   if (unlink (to) && errno != ENOENT)
  2894. #else
  2895.   if (macremove(to) && errno != ENOENT)
  2896. #endif
  2897.     {
  2898.       error ("cannot remove `%s'\n", to);
  2899.       return 1;
  2900.     }
  2901.  
  2902. #ifndef mac
  2903.   ifd = open (from, O_RDONLY, 0);
  2904. #else
  2905.   ifd = open (from, O_RDONLY);
  2906. #endif
  2907.   if (ifd < 0)
  2908.     {
  2909.       error ("%s: open failed\n", from);
  2910.       return errno;
  2911.     }
  2912. #ifndef mac
  2913.   ofd = open (to, O_WRONLY | O_CREAT | O_TRUNC, 0600);
  2914. #else
  2915.   ofd = open (to, O_WRONLY | O_CREAT | O_TRUNC);
  2916. #endif
  2917.   if (ofd < 0)
  2918.     {
  2919.       error ("%s: open failed\n", to);
  2920.       close (ifd);
  2921.       return 1;
  2922.     }
  2923. #ifndef FCHMOD_MISSING
  2924.   if (fchmod (ofd, from_stats.st_mode & 0777))
  2925.     {
  2926.       error ("%s: fchmod failed\n", to);
  2927.       close (ifd);
  2928.       close (ofd);
  2929. #ifndef mac
  2930.       unlink (to);
  2931. #else
  2932.       macremove (to);
  2933. #endif
  2934.       return 1;
  2935.     }
  2936. #endif
  2937.   
  2938.   while ((len = read (ifd, buf, sizeof (buf))) > 0)
  2939.     {
  2940.       int wrote = 0;
  2941.       char *bp = buf;
  2942.       
  2943.       do
  2944.     {
  2945.       wrote = write (ofd, bp, len);
  2946.       if (wrote < 0)
  2947.         {
  2948.           error ("%s: write failed\n", to);
  2949.           close (ifd);
  2950.           close (ofd);
  2951. #ifndef mac
  2952.           unlink (to);
  2953. #else
  2954.           macremove (to);
  2955. #endif
  2956.           return 1;
  2957.         }
  2958.       bp += wrote;
  2959.       len -= wrote;
  2960.     } while (len > 0);
  2961.     }
  2962.   if (len < 0)
  2963.     {
  2964.       error ("%s: read failed\n", from);
  2965.       close (ifd);
  2966.       close (ofd);
  2967. #ifndef mac
  2968.       unlink (to);
  2969. #else
  2970.       macremove (to);
  2971. #endif
  2972.       return 1;
  2973.     }
  2974.  
  2975.   if (close (ifd) < 0)
  2976.     {
  2977.       error ("%s: close failed", from);
  2978.       close (ofd);
  2979.       return 1;
  2980.     }
  2981.   if (close (ofd) < 0)
  2982.     {
  2983.       error ("%s: close failed", to);
  2984.       return 1;
  2985.     }
  2986.   
  2987. #ifdef FCHMOD_MISSING
  2988.   if (chmod (to, from_stats.st_mode & 0777))
  2989.     {
  2990.       error ("%s: chmod failed\n", to);
  2991.       return 1;
  2992.     }
  2993. #endif
  2994.  
  2995.   return 0;
  2996. }
  2997.  
  2998. /* Move FROM onto TO.  Handles cross-filesystem moves.
  2999.    If TO is a directory, FROM must be also.
  3000.    Return 0 if successful, 1 if an error occurred.  */
  3001.  
  3002. int
  3003. do_move (from, to)
  3004.      char *from;
  3005.      char *to;
  3006. {
  3007. #ifndef mac                                        //**REMOVE**
  3008.   if (lstat (from, &from_stats) != 0)
  3009.     {
  3010.       error ("%s: lstat failed\n", from);
  3011.       return 1;
  3012.     }
  3013.  
  3014.   if (lstat (to, &to_stats) == 0)
  3015.     {
  3016. #ifndef MSDOS
  3017.       if (from_stats.st_dev == to_stats.st_dev
  3018.       && from_stats.st_ino == to_stats.st_ino)
  3019. #else
  3020.       if (same_file(from,to))
  3021. #endif
  3022.     {
  3023.       error ("`%s' and `%s' are the same file", from, to);
  3024.       return 1;
  3025.     }
  3026.  
  3027.       if (S_ISDIR (to_stats.st_mode))
  3028.     {
  3029.       error ("%s: cannot overwrite directory", to);
  3030.       return 1;
  3031.     }
  3032.  
  3033.     }
  3034.   else if (errno != ENOENT)
  3035.     {
  3036.       error ("%s: unknown error\n", to);
  3037.       return 1;
  3038.     }
  3039. #ifdef SYSV
  3040.   if (isdir(from)) {
  3041.       char cmd_buf[100];
  3042.       sprintf(cmd_buf, "/usr/lib/mv_dir %s %s", from, to);
  3043.       return system(cmd_buf);
  3044.   } else
  3045. #endif /* SYSV */      
  3046.   if (rename (from, to) == 0)
  3047.     {
  3048.       return 0;
  3049.     }
  3050.  
  3051.   if (errno != EXDEV)
  3052.     {
  3053.       error ("cannot move `%s' to `%s'", from, to);
  3054.       return 1;
  3055.     }
  3056.  
  3057.   /* rename failed on cross-filesystem link.  Copy the file instead. */
  3058.  
  3059.   if (copy (from, to))
  3060.       return 1;
  3061.   
  3062. #ifndef mac
  3063.   if (unlink (from))
  3064. #else
  3065.   if (macremove (from))
  3066. #endif
  3067.     {
  3068.       error ("cannot remove `%s'", from);
  3069.       return 1;
  3070.     }
  3071.  
  3072.   return 0;
  3073. #endif
  3074. }
  3075.     
  3076. /*
  3077.  * do_rename is used by the efun rename. It is basically a combination
  3078.  * of the unix system call rename and the unix command mv. Please shoot
  3079.  * the people at ATT who made Sys V.
  3080.  */
  3081.  
  3082. #ifdef F_RENAME
  3083. int
  3084. do_rename(fr, t)
  3085.     char *fr, *t;
  3086. {
  3087.     char *from, *to;
  3088.     
  3089.     from = check_valid_path(fr, current_object->eff_user, "do_rename", 1);
  3090.     if(!from)
  3091.     return 1;
  3092.     to = check_valid_path(t, current_object->eff_user, "do_rename", 1);
  3093.     if(!to)
  3094.     return 1;
  3095.     if(!strlen(to) && !strcmp(t, "/")) {
  3096.     to = (char *)alloca(3);
  3097.     sprintf(to, "./");
  3098.     }
  3099.     strip_trailing_slashes (from);
  3100.     if (isdir (to))
  3101.     {
  3102.         /* Target is a directory; build full target filename. */
  3103.         char *cp;
  3104.         char *newto;
  3105.         
  3106.         cp = strrchr (from, '/');
  3107.         if (cp)
  3108.         cp++;
  3109.         else
  3110.         cp = from;
  3111.         
  3112.         newto = (char *) alloca (strlen (to) + 1 + strlen (cp) + 1);
  3113.         sprintf (newto, "%s/%s", to, cp);
  3114.         return do_move (from, newto);
  3115.     }
  3116.     else
  3117.     return do_move (from, to);
  3118. }
  3119. #endif /* F_RENAME */
  3120.